I had a problem with a strange behaviour, just found the reason and want to understand what is going on there.
What I observed in debug mode: My Restard method sets gameHasEnded = false and loads the scene again, but after the reload the value of gameHasEnded was still true.
My setup:
A restart button calls the Restart method of my GameManager. This GameManageris a singleton and set to DontDestroyOnLoad.
If I call this restart method by the onClick() event of the button (see following screenshot), it does not use the singleton instance of my GameManager.
I found it out with the following debug logs:
Generating a UUID when the GameManager gets created.
So, when Unity calls the Restart() via the onClick it seems to get somehow a “broken” instance or at least not my singleton.
The line “GameManager.Instance.gameHasEnded = false;” solved my problem that the value was not changed in my singelton, but this seems to be an odd workaround.
Can you explain me why it behaves like observed?
Is it in general not allow to set a reference to a Singleton in the editor?
There should of course only be one instance of a singleton, hence the name. The problem is that we usually want to add it to the scene’s hierarchy and thus a copy of the MonoBehaviour will be created each time the scene is loaded. This can lead to some confusion and the general solution is to check in the Awake() method if there already is a singleton loaded. If there is, we should delete ourselves by calling Destroy().
public class GameManager : MonoBehaviour
{
private static GameManager _instance;
private void Awake()
{
if (_instance != null && _instance != this)
{
// There is already a singleton loaded. Destroy ourself!
Destroy(this.gameObject);
return;
}
// We were first, let this object be the singleton! :)
_instance = this;
DontDestroyOnLoad(this.gameObject);
}
...
If we follow the principle above we shouldn’t add a reference to a public function of the instance, for example from a button. First, it will work as normal. However, when the scene is reloaded, Unity will then again create a new instance of the GameManager and connect it to the button. The second instance will shortly after discover that there already exists an instance and will therefore destroy itself. Nothing will then happen when the user clicks on the button.
If we don’t destroy the second copy, as in your case (I assume), the button will still work even after a reload, but it will be connected to the second instance and you have two singletons (and then three, and then four… and so on).
I would recommend you always delete any instance after the first one. So, how should we connect the button to the first instance? Well, we don’t. We connect it to a static version.
public static void Restart()
{
_instance.gameHasEnded = false;
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
}
So how do we actually connect a static to the button? Do we need to attach a script to the button with that or smth else? Forgive me for being a little clueless as I am a c# noob at the moment :((