DontDestroyOnLoad Leading to Double Objects

Discussion in 'Scripting' started by liquidgraph, Aug 27, 2010.

  1. liquidgraph

    liquidgraph

    New Member

    Joined:
    Feb 26, 2009
    Messages:
    324
    So I have a manager object that controls my whole application. It exists in my starting level and I have it set to "DontDestroyOnLoad".

    Then I load other levels and my manager carries over just fine, but when the player clicks the back button to go back to the main screen (level0), I get a second instance of my manager because it existed originally in that level. Obviously this causes huge problems.

    I thought DontDestroyOnLoad would be smart enough to not replicate the object in question on every level load. Apparently it isn't. What can I do to prevent the controller from getting duplicated? I need it to exist in the first scene to begin with.

    Seems like a chicken and egg problem: I need an object to bootstrap the application, but then I don't need it when reloading the scene.
  2. laurie

    laurie

    New Member

    Joined:
    Aug 31, 2009
    Messages:
    638
    DontDestroyOnLoad() does just that: prevents the object from being destroyed. It doesn't have any effect on when the object gets created.

    One solution is to have a 'bootstrap' level that sets up all such objects and then loads the first real level. You can go back to that level, but you never go back to the bootstrap level.

    Alternatively, use a singleton class not attached to a game object. Since it's not attached to a game object, it's not tied to the game object life-cycle and will not be affected by loading/unloading levels.
  3. liquidgraph

    liquidgraph

    New Member

    Joined:
    Feb 26, 2009
    Messages:
    324
    I need static variables in my object and exposed variables for prefabs and such. This means I can't use a singleton, right? How can I make a singleton but have it start off the scene? Is that possible?

    The bootstrap level will probably work, but seems kludgy -- extra stuff to load on start. I'm targetting the iPhone and want to keep it as efficient as possible.
  4. AkilaeTribe

    AkilaeTribe

    Member

    Joined:
    Jul 4, 2010
    Messages:
    1,149
    Code (csharp):
    1. // CLASS VARIABLES
    2. static var instance : GameSettings;
    3.  
    4. // EVENTS
    5. function Awake ()
    6. {
    7.     if (instance)
    8.     {
    9.         Destroy (gameObject);
    10.     }
    11.     else
    12.     {
    13.         instance = this;
    14.         DontDestroyOnLoad (gameObject);
    15.     }
    16. }
    Comes from a script called GameSettings. Upon Awake, it checks for the content of instance variable (a global variable). If there is nothing, the script put himself in the variable. Future triggering will result in autodestruction, since the place is taken.
  5. liquidgraph

    liquidgraph

    New Member

    Joined:
    Feb 26, 2009
    Messages:
    324
    With that code, which object will get destroyed? The one the game was started with, or the second one that gets loaded upon revisiting the first scene?

    I want my original object to stay intact and not be destroyed because it has variables that need to be preserved. I'm not seeing how that works with this code.

    Awake would be called on both objects once the scene is loaded, so wouldn't they both destroy themselves?!
  6. JRavey

    JRavey

    New Member

    Joined:
    May 12, 2009
    Messages:
    2,377
    If it is something that should persist across every level, you should not really have it in the scene.

    You would have something that instantiates the object if one is not available instead. In C#, I do this.

    Code (csharp):
    1.  
    2.     void Awake () {
    3.         if( FindObjectOfType(typeof(GameStateManager)) == null )
    4.         {
    5.             GameObject newGSM = new GameObject();
    6.             newGSM.name = "GSM";
    7.             newGSM.AddComponent<GameStateManager>();
    8.             GSM = (GameStateManager)newGSM.GetComponent("GameStateManager");
    9.         }
    10.         else
    11.         {
    12.             GSM = (GameStateManager)FindObjectOfType(typeof(GameStateManager));
    13.         }
    14. }
    15.  
    That code has has the camera which drives the menu system link into an existing GameStateManager object if it exists. If it does not exist, such as when the game is first started, it will create it. None of the gameplay scenes create a GameStateManager, because it should already exist.

    This shows a lack of understanding about what scenes are and aren't. Scenes are simply collections of objects. If the scene has the object, it will load the object. As for it being smart enough or not, it is doing exactly what it is supposed to do.
  7. Ntero

    Ntero

    New Member

    Joined:
    Apr 29, 2010
    Messages:
    1,436
  8. liquidgraph

    liquidgraph

    New Member

    Joined:
    Feb 26, 2009
    Messages:
    324
    Thanks for the help guys. I ended up creating a Bootstrapper class that instantiates my game manager using JRavey's code.

    Work's fairly well, although I got one strange null reference exception error that forced me to change a Start() event to an Awake() event to fix. There was a weird problem where one of my array's wasn't being initialized fast enough on Start in one class, but it was being called from another. I'm not sure why instantiating the Manager would cause this problem as nothing else changed. The component scripts attached to the manager remained all the same.
  9. JRavey

    JRavey

    New Member

    Joined:
    May 12, 2009
    Messages:
    2,377
    I think some of that casting is redundant, I'll double check when I get home. I just kind of threw it together one day and never looked back.
  10. Packetstorm

    Packetstorm

    Member

    Joined:
    Jan 6, 2013
    Messages:
    2
    fixed this issue with state code and a bootstrap level thx Laurie nobody else had the right answer