Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

DontDestroyOnLoad inside statement blocks

Discussion in 'Scripting' started by Rodolfo-Rubens, Dec 13, 2015.

  1. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,196
    Or am I missing something, or this is a critical bug with DontDestroyOnLoad behavior:

    The problem is, the DontDestroyOnLoad is being called even if the statement which it is inside is not true. Take a look at the code below to see a even more weirder behavior, after adding only a ! before the statement the DontDestroyOnLoad doesn't get called at all. Can someone try this and explain to me what's happening?

    Code (csharp):
    1.  
    2. // Create two scenes: Scene1 and Scene2
    3. // In the scene 1 create a GameObject (a cube for instance) and add this script
    4. // Play the scene 1 and try the scene toggling the dontDestroy value and pressing the load scene x to scene if it works as expected
    5.  
    6. using UnityEngine;
    7. using UnityEngine.SceneManagement;
    8. using System.Collections;
    9.  
    10. public class PleaseDontDestroy : MonoBehaviour {
    11.  
    12.     public bool dontDestroy;
    13.  
    14.     void Awake()
    15.     {
    16.         print("Awaking");
    17.  
    18.         //if(!dontDestroy) // <== this is even wierder, the DontDestroyOnLoad doens't work at all when inside a block with this statement, even if the statement is true
    19.         if(dontDestroy)
    20.         {
    21.             print("dontDestroy is " + dontDestroy);
    22.             DontDestroyOnLoad(gameObject); // doesn't work
    23.  
    24.             //DontDestroy(); //doesn't work too
    25.         }
    26.         else
    27.         {
    28.             Destroy(gameObject);
    29.             print("dontDestroy is " + dontDestroy);
    30.         }
    31.     }
    32.  
    33.     void DontDestroy()
    34.     {
    35.         print("dontDestroy is " + dontDestroy);
    36.         DontDestroyOnLoad(gameObject); // <== BEING CALLED EVEN IF DONT DESTROY IS FALSE
    37.     }
    38.  
    39.     void OnGUI()
    40.     {
    41.         GUILayout.Label("Current scene: " + SceneManager.GetActiveScene().name);
    42.  
    43.         if(SceneManager.GetActiveScene().name == "Scene1")
    44.         {
    45.             if(GUILayout.Button("Load scene 2"))
    46.             {
    47.                 SceneManager.LoadScene("Scene2");
    48.             }          
    49.         }
    50.         else if(GUILayout.Button("Load scene 1"))
    51.         {
    52.             SceneManager.LoadScene("Scene1");
    53.         }
    54.  
    55.         dontDestroy = GUILayout.Toggle(dontDestroy, "Dont destroy?");
    56.     }
    57. }
    58.  
    DontDestroyOnLoad gets called no matter where it is inside the code? But then, what about the line 18? What's happening?

    if you are too lazy I attached a package.

    edit: I think Awake is not being called when it should.
     

    Attached Files:

  2. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,196
    Ok, I think I got it, Awake is only called once in the lifetime of a gameObject, ok! So if this only time Awake was called the DontDestroyOnLoad was called too, the game object (or whatever object you passed) will not be destroyed when a new scene loads. This object will never be destroyed when another scene loads, never, unless you call destroy yourself using Destroy, it's like a toggle that can't be switched off, once you call DontDestroyOnLoad, there is no way to call something like DestroyOnLoad and this condition is not reset in any way.
    Am I right?

    This is very bad!!
     
  3. iwaldrop

    iwaldrop

    Joined:
    Sep 3, 2012
    Posts:
    9
    I guess the question is what kind of script or game object would you want to flag as sometimes don't destroy on load?

    To solve you problem though, it seems like you can flag the object to not be destroyed in awake and when a level loads evaluate your condition again in OnLevelWasLoaded to manually destroy it yourself if you don't want it anymore.
     
    Rodolfo-Rubens likes this.
  4. Rodolfo-Rubens

    Rodolfo-Rubens

    Joined:
    Nov 17, 2012
    Posts:
    1,196
    Hey @iwaldrop, thanks for your suggestion! I think that's the only solution, in my case I'm destroying even after, I always need to reread about Awake because I always think that it will be called every scene load, I hope this time that enter in my head! That mistake also made me think that if the DontDestroyOnLoad is being called it will not destroy, and if it's not, it will be destroyed on scene load, even if the DontDestroyOnLoad was already called on that object and I was very wrong, I even sent a bug report :confused:! Anyway, now I know! Thank you very much.

    I created a simple script to manage a couple of things better, it keeps unique copies of game objects based on the game object name, tag or a unique string:
    Code (csharp):
    1.  
    2. // Keep unique copies of objects
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. public class PersistentObject : MonoBehaviour
    7. {
    8.     [HideInInspector] public int awakeFrame;
    9.     [SerializeField] bool keepAsUnique = false;
    10.     [SerializeField] UniqueCheck checkBy = UniqueCheck.Name;
    11.     [SerializeField] string uniqueString;
    12.     [SerializeField] bool dontDestroy = true;
    13.     [SerializeField] bool destroyOlder = false;
    14.  
    15.     void Awake()
    16.     {
    17.         awakeFrame = Time.frameCount;
    18.  
    19.         if(dontDestroy) DontDestroyOnLoad(gameObject);
    20.  
    21.         if(keepAsUnique) CheckForDuplicates();
    22.     }
    23.  
    24.     void OnLevelWasLoaded()
    25.     {
    26.         if(!dontDestroy) Destroy(gameObject);
    27.     }
    28.  
    29.     void CheckForDuplicates()
    30.     {
    31.         var allObjects = FindObjectsOfType<PersistentObject>();
    32.         foreach(var obj in allObjects)
    33.         {
    34.             if(obj == this) continue;
    35.             PersistentObject duplicate = null;
    36.  
    37.             switch(checkBy)
    38.             {
    39.             case UniqueCheck.Name:
    40.                 if(gameObject.name == obj.name) duplicate = obj;
    41.                 break;
    42.             case UniqueCheck.Tag:
    43.                 if(gameObject.tag == obj.tag) duplicate = obj;
    44.                 break;
    45.             case UniqueCheck.UniqueString:
    46.                 if(uniqueString == obj.uniqueString) duplicate = obj;
    47.                 break;
    48.             }
    49.  
    50.             if(duplicate != null)
    51.             {
    52.                 DestroyDuplicate(duplicate);
    53.             }
    54.         }
    55.     }
    56.  
    57.     void DestroyDuplicate(PersistentObject duplicate)
    58.     {
    59.         if(!destroyOlder)
    60.         {
    61.             if(duplicate.awakeFrame > awakeFrame) Destroy(duplicate.gameObject);
    62.             else
    63.             {
    64.                 //print(gameObject + " is destroying itself.");
    65.                 Destroy(gameObject);
    66.             }          
    67.         }
    68.         else
    69.         {
    70.             if(duplicate.awakeFrame < awakeFrame) Destroy(duplicate.gameObject);
    71.             else
    72.             {
    73.                 //print(gameObject + " is destroying itself.");
    74.                 Destroy(gameObject);
    75.             }  
    76.         }
    77.     }
    78.  
    79.     public static GameObject FindPersistentWithUniqueString(string uniqueString)
    80.     {
    81.         var allObjects = FindObjectsOfType<PersistentObject>();
    82.         foreach(var obj in allObjects)
    83.         {
    84.             if(obj.uniqueString == uniqueString) return obj.gameObject;
    85.         }
    86.  
    87.         return null;
    88.     }
    89. }
    90.  
    91. [System.Serializable]
    92. public enum UniqueCheck
    93. {
    94.     Name,
    95.     Tag,
    96.     UniqueString
    97. }
    98.