Search Unity

Question GameManager references between load scenes

Discussion in 'Getting Started' started by Nayas, Sep 27, 2021.

  1. Nayas

    Nayas

    Joined:
    Sep 10, 2021
    Posts:
    3
    Hello Everyone,

    I am new to Unity and started a week ago.
    I am going through a book (Developing 2D Games with Unity) and some YT video (mainly this one) to learn the Unity basis, mostly 2D stuff at the moment.

    I have a question about references between scene load. I have a problem with my dummy project and I do not understand why it does not behave as it should.

    I have a GameManager object, which holds some values and references (player, text, ennemi).
    As I read on this forum/reddit/stackoverflow, I am running this code :

    Code (CSharp):
    1.     public static GameManager instance;
    2.  
    3.     private void Awake()
    4.     {
    5.         if (GameManager.instance != null)
    6.         {
    7.             Destroy(gameObject);
    8.             return;
    9.         }
    10.  
    11.         instance = this;
    12.         SceneManager.sceneLoaded += LoadState;
    13.         DontDestroyOnLoad(gameObject);
    When I move to a locate that load another screen, I lose the references to the player, enemy and weapon.
    I still have the values for the other int that I save in SaveState() and load in LoadState().

    I tried to remove the Destroy(gameObject); line, to see the difference between both GameManager object.

    The original one has no references anymore to the player, enemy and weapon but has the value for some other int.
    The newly created GameManager has references to player, enemy and weapon but has no values to the other int values.

    I added some Debug.Log(""); text in the awake to follow the execution and it seems to be OK.
    I do not understand the behavior and how I can fix it.

    Anyone could share some help on problem?

    Thanks!
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'll see if I can help you understand what's going on.

    OK. Some of those values are integers, I guess. Those can survive a scene change just fine; 42 exists everywhere and is no problem to keep around.

    But now consider references to things in the scene: the player, some UI text, an enemy gameobject. All those objects disappear when the scene you're in is unloaded. Poof, gone, they exist no more. When the scene is unloaded, all scene objects that nobody has called DontDestroyOnLoad are, in fact, destroyed. And in Unity, when you have a reference to an object that no longer exists, it effectively becomes null.

    Now the new scene you're loading may have some other objects that greatly resemble these objects from your first scene. There may be something called "player" for example. But that's not good enough. Unity does not match things up by name. That new "player" object has no relationship whatsoever (as far as Unity is concerned) to the old player object from the first scene. Likewise for the text, enemy, etc.

    You didn't say so, but I'm guessing that in the new scene you also have a new GameManager. And that new GameManager has references to these objects in the new scene. That'd be fine, except you found some code on the internet and dropped it into your project without understanding it:

    Yikes. Let's look at what this code does. In the Awake method — which is the very first thing that runs for this object when the scene is loaded — it says: if there is another GameManager instance (for example, from a previous scene), then destroy this one. If not, then make this one the One True GameManager, the only one that will ever exist, and set it to survive scene changes.

    So this works fine in the first scene; but when you load the second scene, the new GameManager sees that another one already exists, and quietly destroys itself.

    Of course you do. The GameObject that had those references just destroyed itself. What you're looking at is the old GameManager from the first scene, and the objects it had references to no longer exist.

    Right (and this was a clever test, good job there). I hope it's clear now. The original one had references to objects that were destroyed, so those now appear null. And the new one has whatever int values you set for it in its scene, not whatever values were set or changed in the first scene.

    Probably you should take out the code above. If your GameManager's job is to hold references to things in the scene, then this singleton pattern is not appropriate. As for int values and such that you want to survive scene changes, you can simply make those static, and they will be shared by all GameManagers in all scenes.
     
    Joe-Censored likes this.
  3. Nayas

    Nayas

    Joined:
    Sep 10, 2021
    Posts:
    3
    Hello @JoeStrout

    Thank you very much for the clear explanation. I am still learning the basic concepts ;)

    As you said, I am following a tutorial and using the code and then I try to understand it by reading the Unity Doc and "playing" the modification. I think by removing the Destroy(gameObject); line and checking both objects, I had the answer "in front of my eyes" without understanding it.

    Otherwise, I was actually getting ahead of myself. The tutorial dealt with the object persistence later on.
    Baby step first, followed by another baby step. Same with various options to have object persistence between scenes.

    Thank you!
     
    JoeStrout likes this.
  4. Zaerick

    Zaerick

    Joined:
    Sep 11, 2021
    Posts:
    37
    Fairly new as well and just learned about the singleton method not long ago. Wouldn't creating a prefab for the objects he wants to keep fix his issue?
     
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    No. In this case I'm pretty sure he doesn't want references to prefabs in the project; he wants references to objects already laid out in the scene.
     
    Zaerick and Joe-Censored like this.