Game behaves differently when I build and run it

Hi
I have come across a problem I find very odd. When I try to build and run my game, my GameManager class is supposedly NULL when referring it from a GameObject. This should not happen because i’ve confirmed that the GameManager is actually created beforehand.

I have a typical commonly used Singleton GameManager class (which is of course assigned to a gameobject and all that):

public class GameManager : MonoBehaviour
{
    private static GameManager _instance;
    public static GameManager Instance
    {
        get
        {
            if (_instance == null)
                Debug.LogError("Game Manager is null!");
      
            return _instance;
        }
    }
    private void Awake()
    {
        if (_instance == null) {
            Debug.Log("##### GameManager: DontDestroyOnLoad and setting GameManager instance with ID=" + gameObject.GetInstanceID());
            DontDestroyOnLoad(this.gameObject);
            _instance = this;
        } else {
            Debug.Log("##### GameManager: Destroying GameManager with ID=" + gameObject.GetInstanceID());
            Destroy(gameObject);
}

Worth mentioning is that the game works fine (even with scene changes) when I play it through Unity… But whenever I build the project and execute the EXE file and run the game, it suddenly starts getting a different behaviour. What could be the reason for this? I couldn’t find anything when googling about it. it’s like the lifetime of certain objects are different.

Nevertheless, the main problem that makes me confused is that whenever the Boss-object enters the screen, it tries to access the GameManager and it results in NullPtrReference:

GameManager.Instance.setAutoScrollInactive();

Some strange observations i’ve made is that:

  1. The Debug.Log prints actually can show that the GameManager IS created before accessing it.
  2. The Awake from GameManager should be called before the Boss’s OnBecameVisible in any case right?
  3. The Boss’s OnBecameVisible doesn’t even get triggered before a couple of seconds in when starting the game, so it shouldn’t be a problem regardless.

Still for some reason the Boss class OnBecameVisible() results in:
NullReferenceException: Object reference not set to an instance of an object
at Boss.OnBecameVisible () [0x00008] in D:#####\Assets\Scripts\Enemies\Boss.cs:27
The line in question is this:
GameManager.Instance.setAutoScrollInactive();

Another strange observation here is that when I change the above line to a null check like this:
if (GameManager.Instance == null) {
Debug.LogError(“Test debug log”);
}
I don’t get that debug message. How is this possible?


So long story short, I have no idea why this happens and I find it very odd that I cannot even null check it when I know it’s a NullRef problem and everything…

Here is the full log:

##### GameManager: DontDestroyOnLoad and setting GameManager instance with ID=3700 <------ GameManager is created
UnityEngine.StackTraceUtility:ExtractStackTrace ()
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[ ])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
GameManager:Awake () (at D:/#####/Assets/Scripts/GameManager.cs:29)
(Filename: D:/#####/Assets/Scripts/GameManager.cs Line: 29)
Unloading 6 Unused Serialized files (Serialized files now loaded: 0)
UnloadTime: 8.162500 ms
##### GameManager: Destroying GameManager with ID=4082 <------ Another GameManager is being created, but destroyed
UnityEngine.StackTraceUtility:ExtractStackTrace ()
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[ ])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
GameManager:Awake () (at D:/#####/Assets/Scripts/GameManager.cs:33)
(Filename: D:/#####/Assets/Scripts/GameManager.cs Line: 33)
Unloading 6 unused Assets / (2.0 KB). Loaded Objects now: 2373.
Memory consumption went from 41.6 MB to 41.6 MB.
Total: 1.285600 ms (FindLiveObjects: 0.119800 ms CreateObjectMapping: 0.080200 ms MarkObjects: 1.054900 ms DeleteObjects: 0.030400 ms)
NullReferenceException: Object reference not set to an instance of an object
at Boss.OnBecameVisible () [0x00008] in D:\#####\Assets\Scripts\Enemies\Boss.cs:27 
(Filename: D:/#####/Assets/Scripts/Enemies/Boss.cs Line: 27)

I wouldn’t do a singleton that way… it won’t work in all cases, plus it’s like 2x the lines of code you actually need.

Simple Singleton (UnitySingleton):

Some super-simple Singleton examples to take and modify:

Simple Unity3D Singleton (no predefined data):

Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

These are pure-code solutions, DO NOT put anything into any scene, just access it via .Instance!

If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

public void DestroyThyself()
{
   Destroy(gameObject);
   Instance = null;    // because destroy doesn't happen until end of frame
}

There are also lots of Youtube tutorials on the concepts involved in making a suitable GameManager, which obviously depends a lot on what your game might need.

OR just make a custom ScriptableObject that has the shared fields you want for the duration of many scenes, and drag references to that one ScriptableObject instance into everything that needs it. It scales up to a certain point.

If you really insist on a barebones C# singleton, here’s a highlander (there can only be one):

And finally there’s always just a simple “static locator” pattern you can use on MonoBehaviour-derived classes, just to give global access to them during their lifecycle.

WARNING: this does NOT control their uniqueness.

WARNING: this does NOT control their lifecycle.

public static MyClass Instance { get; private set; }

void OnEnable()
{
  Instance = this;
}
void OnDisable()
{
  Instance = null;     // keep everybody honest when we're not around
}
2 Likes

Hehe.

Thank you for the detailed answer. I will check out the examples you provided