Multible values of variable?!?

I’m having trouble comprehending what is happening here.

using UnityEngine;
using System.Collections;

public class MyClass : MonoBehaviour {

	private static MyClass instance = null;
	public static MyClass get {
		get {
			if (!instance)
				instance = FindObjectOfType(typeof(MyClass)) as MyClass;
			
			return instance;
		}	
	}
	
	public void Start() {
		Debug.Log(GetInstanceID());
		Debug.Log(b, this);
		Debug.Log(get.GetInstanceID());
		Debug.Log(get.b, get);
	}
	
	public bool b = false;
	
	void Update () {
		if (Input.GetMouseButtonDown(0)) {
			b = true;
		}
	}
}

If you attach this script to a gameObject and run the scene it prints:

xxx (InstanceID)
false
xxx (Same ID)
false

which is what you’d expect.
Now if you click the mouse, stop the scene and play it again it prints:

xxx (InstanceID)
false
xxx (Same ID)
true

How on earth can my script have two values for same variable? Or perhaps more properly states, since that’s obviously preposterous. How can I have gotten two instances of the script with the same ID?

This only happens in the editor. Static variables are not cleared when exiting and entering play mode. Therefore static variables risk containing garbage from earlier runs.

To work around this, simply reset all static variables inside Awake:

public void Awake() { 
    instance = null;
}

I’ve had this problem before… highly confusing!

Freyr’s suggestion is good, but I’d recommend clearing the static variables in OnApplicationQuit instead of Awake. That means they’ll be reset at the end of the game, and when the game starts next time they’re already be null before Awake is called on any of the objects in the scene.

If you do it in Awake, there’s a danger that some other object’s Awake method will be called before yours, and if it tries to call your get() method, you’ll end up with two separate instances of the object again.

Actually I’ll have to use both Awake and OnApplicationQuit to make it work, as this class (well, the one it represents) is used both in editor mode as well as in game mode. But I still don’t understand why I need to do this? Consider the following script attached to the only gameObject in a scene:

using UnityEngine;
using System.Collections;

public class MyClass : MonoBehaviour {

	private static MyClass instance = null;
	public static MyClass get {
		get {
			if (!instance)
				instance = FindObjectOfType(typeof(MyClass)) as MyClass;
			
			return instance;
		}	
	}
	
	public bool b = false;
	public void Awake() {
		Debug.Log(instance == this);
	}

	[ContextMenu("Print")]
	private void PrintB() {
		Debug.Log(b);
		Debug.Log(get.b);			
	}
}
  1. First I select the object and call PrintB thought the contextMenu.
  2. This will print the value b, which is false.
  3. It will then (by calling get) invoke FindObjectOfType in the scene and find the same instance of the script I have just invoked PrintB on, as it’s the only one in existence, remember this instance in a static variable and print the value of b (the same b as before) which is, predictable, false.
  4. I then press “play” and Awake confirms that the instance of the script on the gameObject is the same instance as the one referenced by the static variable.
  5. I then set b to true by clicking on it in the inspector and invoke PrintB through the context menu again.
  6. This print true which is the expected value of b on this scripts, but it then prints false as the value of b on the instance reference by the static variable. But this is/should be the very same instance as the one I called PrintB on! Awake even confirmed it.

PS: Sorry to be a bother, but I’m much more interested in understanding why this doesn’t work than a solution/workaround.

Clearing in OnApplicationQuit() can also give you some nasty bugs. If another script has OnApplicationQuit and uses YourManager.instance after YourManager.OnApplicationQuit() is called… ouch. It happened for me in the Brain Games but luckily I figured it out pretty quickly.

So just a heads up. :slight_smile:

-Jon