Null Reference Exeption with Singletons (2d Pixel Combat)

During the course 2D topDownPixelCombat in one moment (I dont know exactly when) I encountered an issue with null reference exeptions - my default weapon stopped to spawn and entire weapon system stopped working. Console was throwing some strange null reference exceptions (I don’t have them screenshotted, sorry). Before (some random step not connected at all with weapon system) it all worked well.

What turned out was that one of the singletons (Active Weapon to be precise) was not initialized before other scripts wanted to reference it, and because of that a static Instance of ActiveWeapon was not yet created and caused NRE.
The solution for me was to go to Script Execution Order settings and plop the ActiveWeapon before Default Time.

Is this normal behavior for Singletons in Unity? Id guess it is, as they are all Instantiated in Awake (at least in this implementation?), and there is no way of telling which Awake is running first (other than script execution order ofc).
I think it might be worth mentioning this problem in this course, because it uses Singletons quite extensively.

This is common and the golden rule is; don’t access other components in Awake(). You can set up things like cached components with GetComponent, etc., but don’t call anything on them. Do that in Start()

1 Like

Ah, yes! This makes sense. Thanks, I will (probably) remember it now :wink:

Quite normal. Outside of Script Execution Order (be VERY careful not to change the order of any of the pre-existing classes within the SEO settings or they’ll break), there are some simple rules I follow to avoid these situations:

  • Awake() – Cache references on the same GameObject, do not access them yet. Cache external references via FindObjectOfType or FindWithTag, but not Singletons. Initialize any reference values that belong to the class here as well, for example: myDictionary = new ();
  • OnEnable() – Subscribe to events here, Unsubscribe in OnDisable()
  • Start()/Update() – You are now free to access the references you cached along with Singletons.
2 Likes

Thanks for clarification and your rules - they are helpful to understand.
Thanks to both of you I understand better how to use Awake and Start.

I did check what precisely I got wrong, and it was calling internal function of my class in Awake instead of Start. This function was calling another function and that third function was referencing the Singleton. Well, quite convoluted…

Now, I guess I will remember not to call anything on Awake, unless it is base.Awake() :wink:

1 Like

That’s an easy trap to fall into even when you’re not using a Singleton.
I should note that Singletons can create complications if, instead of using the Singleton, you say "Oh, I can just FindWithTag to get the player for now, and use the Singleton later in the code… If there’s a player in every scene, then it’s possible for the player in the scene to be caught up in the FindWithTag() before the Singleton code runs to destroy it. A DontDestroyOnLoad gameObject is actually put into it’s own “Scene” in the heirarchy called DontDestroyOnLoad and remove from the current scene once it goes Singleton. So if there’s a player in the scene and you get a reference to it by mistake before it nukes itself, a FindWithTag or FindObjectOfType will always find that character first (because both of these methods go through the main scene, and then the DontDestroyOnLoad scene).
I only mention it because my rules do say you can get references to FindWithTag and FindObjectOfType GameObjects. That won’t work if the class is a Singleton.

1 Like

Privacy & Terms