Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Editor script: How to access objects under DontDestroyOnLoad while in Play mode

Discussion in 'Scripting' started by yasirkula, Nov 20, 2016.

  1. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Hi there,

    I believe the title is pretty self-explanatory. I want to access the root GameObject's that are listed under the DontDestroyOnLoad scene while the editor is in Play mode.

    Any help is appreciated.
     
  2. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,186
    DontDestroyOnLoad are just objects that move around from scene to scene. There are several ways to access them. One is just to do a script with a static variable of itself and you can just reference that script through that variable.

    Another common way is you just know what the object name is and you find it.
    So if the gameobject name is "GameData" for example and then you want to access it in a new scene after switching, you'd use a GameObject.Find("GameData") call somewhere to do so and that will allow you to find the GameObject. You'll then access it's scripts with GetComponent like you normally would.
     
  3. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Thank you for your comment. I am not looking for a specific component on a DontDestroyOnLoad game object and, unfortunately, I don't know the names of the game objects I am looking for. I just know that they are listed under the DontDestroyOnLoad scene in Hierarchy.

    Normally, I access root game objects in a scene using UnityEngine.SceneManagement.Scene.GetRootGameObjects but I can't find a way to access the DontDestroyOnLoad scene, so I am pretty clueless right now.
     
    lucbloom likes this.
  4. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    OK; apparently this one works but this looks terribly ugly. It will also be extremely slow but it won't be an issue for my case (an editor script). Still looking for better solutions, though...

    Code (CSharp):
    1. public static List<GameObject> GetDontDestroyOnLoadObjects()
    2. {
    3.     List<GameObject> result = new List<GameObject>();
    4.  
    5.     List<GameObject> rootGameObjectsExceptDontDestroyOnLoad = new List<GameObject>();
    6.     for( int i = 0; i < SceneManager.sceneCount; i++ )
    7.     {
    8.         rootGameObjectsExceptDontDestroyOnLoad.AddRange( SceneManager.GetSceneAt( i ).GetRootGameObjects() );
    9.     }
    10.  
    11.     List<GameObject> rootGameObjects = new List<GameObject>();
    12.     Transform[] allTransforms = Resources.FindObjectsOfTypeAll<Transform>();
    13.     for( int i = 0; i < allTransforms.Length; i++ )
    14.     {
    15.         Transform root = allTransforms[i].root;
    16.         if( root.hideFlags == HideFlags.None && !rootGameObjects.Contains( root.gameObject ) )
    17.         {
    18.             rootGameObjects.Add( root.gameObject );
    19.         }
    20.     }
    21.  
    22.     for( int i = 0; i < rootGameObjects.Count; i++ )
    23.     {
    24.         if( !rootGameObjectsExceptDontDestroyOnLoad.Contains( rootGameObjects[i] ) )
    25.             result.Add( rootGameObjects[i] );
    26.     }
    27.  
    28.     //foreach( GameObject obj in result )
    29.     //    Debug.Log( obj );
    30.  
    31.     return result;
    32. }
     
    lucbloom, Gargosian and waltran like this.
  5. paulomuggler

    paulomuggler

    Joined:
    Mar 18, 2014
    Posts:
    4
    Very nicely done, thank you.
     
  6. roddles

    roddles

    Joined:
    Jan 22, 2014
    Posts:
    3
    After encountering this issue and then reading up more on Multi-Scene and DontDestroyOnLoad, the best practice is to avoid using DontDestroyOnLoad when using multiple scene techniques. In fact, Unity has considered deprecating DDOL due to the confusion. With the ability to dynamically add and remove scenes per the developer's will, the DDOL mechanism is no longer necessary, (it is in fact an artifact that remains from before Unity 5.3, when Scene Management was added).

    The preferred solution is to place objects in a scene that remains loaded, and then scripts should find and load said objects from the persistent scene using the scene management API.

    Links:
    Playmode heading, and Last tip under Tips & Tricks Heading: https://docs.unity3d.com/Manual/MultiSceneEditing.html
     
  7. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    Thank you for sharing it. The suggested solution in the documentation seems acceptable but I believe many people will still keep using DontDestroyOnLoad as it is super-easy to setup, just one line of code. And plenty of plugins out there already use DDOL for their singletons. For me, it would be very surprising to see Unity deprecating DDOL. But again, thanks for the link.
     
    Xtro, bebaoboy and OfficialHermie like this.
  8. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    After a long time, here's a much better way to get DontDestroyOnLoad objects, lol:

    Code (CSharp):
    1. public static GameObject[] GetDontDestroyOnLoadObjects()
    2. {
    3.     GameObject temp = null;
    4.     try
    5.     {
    6.         temp = new GameObject();
    7.         Object.DontDestroyOnLoad( temp );
    8.         UnityEngine.SceneManagement.Scene dontDestroyOnLoad = temp.scene;
    9.         Object.DestroyImmediate( temp );
    10.         temp = null;
    11.  
    12.         return dontDestroyOnLoad.GetRootGameObjects();
    13.     }
    14.     finally
    15.     {
    16.         if( temp != null )
    17.             Object.DestroyImmediate( temp );
    18.     }
    19. }
     
    Xtro, DSivtsov, NibbleByte3 and 17 others like this.
  9. TheBeardPhantom

    TheBeardPhantom

    Joined:
    Dec 10, 2013
    Posts:
    7
    This will not work in a build. Quoting https://docs.unity3d.com/Manual/MultiSceneEditing.html:

     
    thilak02, OfficialHermie and Peter77 like this.
  10. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    That's what I thought, as well, but it worked for me on a standalone build for a Unity version that I don't remember. Either way, it should work in the Editor.
     
    thilak02 and Claytonious like this.
  11. BjoernS

    BjoernS

    Joined:
    Nov 14, 2012
    Posts:
    5
    Thanks for your scripts and inspiration! This worked for me:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. // use as "spy" to get all the roots from DontdestroyOnLoad from the "inside" :)
    4. public class DontdestroyOnLoadAccessor : MonoBehaviour
    5. {
    6.     private static DontdestroyOnLoadAccessor _instance;
    7.     public static DontdestroyOnLoadAccessor Instance {
    8.         get {
    9.             return _instance;
    10.         }
    11.     }
    12.  
    13.     void Awake()
    14.     {
    15.         if (_instance != null) Destroy(this);
    16.         this.gameObject.name = this.GetType().ToString();
    17.         _instance = this;
    18.         DontDestroyOnLoad(this);
    19.     }
    20.  
    21.     public GameObject[] GetAllRootsOfDontDestroyOnLoad() {
    22.         return this.gameObject.scene.GetRootGameObjects();
    23.     }
    24. }
    25.  
    26. // Example to access the dontdestroy-objects from anywhere
    27. public class FindDontDestroyOnLoad : MonoBehaviour
    28. {
    29.     public GameObject[] rootsFromDontDestroyOnLoad;
    30.     void Start()
    31.     {
    32.         rootsFromDontDestroyOnLoad = DontdestroyOnLoadAccessor.Instance.GetAllRootsOfDontDestroyOnLoad();
    33.     }
    34. }
    35.  
     
  12. TenaciousDan

    TenaciousDan

    Joined:
    Jul 11, 2019
    Posts:
    30
    The method described above to get root game objects from the special "DontDestroyOnLoad" scene:
    Code (CSharp):
    1. ddolGameObject.scene.GetRootGameObjects();
    works with no errors with Unity 2020.1 even after I build the game and run it.

    Does anyone know when this was fixed??? I'm writing a script and need to check if this is supported for the user's unity version.
     
    thilak02 likes this.
  13. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    I use it in RuntimeInspector and it seems to work fine on 5.6 and later (don't know about older versions).
     
  14. dvalles

    dvalles

    Joined:
    Nov 15, 2014
    Posts:
    11
    Really clever, thank you
     
    thilak02 likes this.
  15. iJezoul07

    iJezoul07

    Joined:
    Jul 8, 2020
    Posts:
    2
    Can you please explain how it works please?
     
    OfficialHermie likes this.
  16. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
  17. iJezoul07

    iJezoul07

    Joined:
    Jul 8, 2020
    Posts:
    2
    Can you please tell me please where do I put this?
     
  18. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    In the script that you want to access DontDestroyOnLoad objects from. Then you can call GetDontDestroyOnLoadObjects() function to get these objects.
     
  19. OfficialHermie

    OfficialHermie

    Joined:
    Oct 12, 2012
    Posts:
    585
    What you say doesn't seem to make sense to me. What is a "persistent scene"? The only "persistent scene" samples that I found using Google were scenes that were made persistent with DontDestroyOnLoad.
     
  20. vamosfa

    vamosfa

    Joined:
    May 15, 2016
    Posts:
    59
    Hi, it is an interesting debate according to what I am looking for.

    Do you know if it is possible to execute don't destroy on load in edit mode? I mean, of course, I use it on Runtime, but it would extremely useful for testing purposes could do it in Edit Mode, just double-clicking from one scene of the project folder to another one. Thanks
     
  21. yasirkula

    yasirkula

    Joined:
    Aug 1, 2011
    Posts:
    2,865
    In the editor, AFAIK, setting a GameObject's hideFlags to DontSave will do the job but I really don't know what exactly are the caveats.
     
    Bunny83 likes this.
  22. Rylan523

    Rylan523

    Joined:
    May 26, 2022
    Posts:
    2
    aleksandr19982012 likes this.
  23. tpktpk

    tpktpk

    Joined:
    Dec 11, 2022
    Posts:
    2
  24. Xtro

    Xtro

    Joined:
    Apr 17, 2013
    Posts:
    604
    Thank you very much for sharing this!!!
     
    yasirkula likes this.
  25. nndwn_

    nndwn_

    Joined:
    Nov 7, 2018
    Posts:
    3
    maybe someone confused how use this code,
    if you trouble reference use this

    using Object = UnityEngine.Object;

    how use this code
    Code (CSharp):
    1.  
    2.  
    3. public  static class GetDataOnDestroy
    4. {
    5. public static GameObject[] GetDontDestroyOnLoadObjects()
    6. {
    7.     GameObject temp = null;
    8.     try
    9.     {
    10.         temp = new GameObject();
    11.         Object.DontDestroyOnLoad( temp );
    12.         var dontDestroyOnLoad = temp.scene;
    13.         Object.DestroyImmediate( temp );
    14.         temp = null;
    15.  
    16.         return dontDestroyOnLoad.GetRootGameObjects();
    17.     }
    18.     finally
    19.     {
    20.         if( temp != null )
    21.             Object.DestroyImmediate( temp );
    22.     }
    23. }
    24.  
    25. }
    26. public class Sample : MonoBehaviour
    27. {
    28. public GameObject trasitionScene; // i want get data DontDestroyOnLoadObjects
    29. public Image image; // i want get data child in DontDestroyOnLoadObjects
    30.  
    31. private void Start()
    32. {
    33.  
    34. trasitionScene = GetDataOnDestroy.GetDontDestroyOnLoadObjects()[0];
    35. image = GetDataOnDestroy.GetDontDestroyOnLoadObjects()[0].tranform.Find(
    36. "Canvas/Image").GetComponent<Image>();
    37.  
    38. }
    39. }
    40.  
    41.  
    42.  
    43.