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

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.

6 Likes

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.

7 Likes

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.

1 Like

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…

public static List<GameObject> GetDontDestroyOnLoadObjects()
{
    List<GameObject> result = new List<GameObject>();

    List<GameObject> rootGameObjectsExceptDontDestroyOnLoad = new List<GameObject>();
    for( int i = 0; i < SceneManager.sceneCount; i++ )
    {
        rootGameObjectsExceptDontDestroyOnLoad.AddRange( SceneManager.GetSceneAt( i ).GetRootGameObjects() );
    }

    List<GameObject> rootGameObjects = new List<GameObject>();
    Transform[] allTransforms = Resources.FindObjectsOfTypeAll<Transform>();
    for( int i = 0; i < allTransforms.Length; i++ )
    {
        Transform root = allTransforms[i].root;
        if( root.hideFlags == HideFlags.None && !rootGameObjects.Contains( root.gameObject ) )
        {
            rootGameObjects.Add( root.gameObject );
        }
    }

    for( int i = 0; i < rootGameObjects.Count; i++ )
    {
        if( !rootGameObjectsExceptDontDestroyOnLoad.Contains( rootGameObjects[i] ) )
            result.Add( rootGameObjects[i] );
    }

    //foreach( GameObject obj in result )
    //    Debug.Log( obj );

    return result;
}
3 Likes

Very nicely done, thank you.

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: Unity - Manual: Work with multiple scenes in Unity

6 Likes

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.

3 Likes

After a long time, here’s a much better way to get DontDestroyOnLoad objects, lol:

public static GameObject[] GetDontDestroyOnLoadObjects()
{
    GameObject temp = null;
    try
    {
        temp = new GameObject();
        Object.DontDestroyOnLoad( temp );
        UnityEngine.SceneManagement.Scene dontDestroyOnLoad = temp.scene;
        Object.DestroyImmediate( temp );
        temp = null;

        return dontDestroyOnLoad.GetRootGameObjects();
    }
    finally
    {
        if( temp != null )
            Object.DestroyImmediate( temp );
    }
}
24 Likes

This will not work in a build. Quoting https://docs.unity3d.com/Manual/MultiSceneEditing.html:

3 Likes

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.

2 Likes

Thanks for your scripts and inspiration! This worked for me:

using UnityEngine;

// use as "spy" to get all the roots from DontdestroyOnLoad from the "inside" :)
public class DontdestroyOnLoadAccessor : MonoBehaviour
{
    private static DontdestroyOnLoadAccessor _instance;
    public static DontdestroyOnLoadAccessor Instance {
        get {
            return _instance;
        }
    }

    void Awake()
    {
        if (_instance != null) Destroy(this);
        this.gameObject.name = this.GetType().ToString();
        _instance = this;
        DontDestroyOnLoad(this);
    }

    public GameObject[] GetAllRootsOfDontDestroyOnLoad() {
        return this.gameObject.scene.GetRootGameObjects();
    }
}

// Example to access the dontdestroy-objects from anywhere
public class FindDontDestroyOnLoad : MonoBehaviour
{
    public GameObject[] rootsFromDontDestroyOnLoad;
    void Start()
    {
        rootsFromDontDestroyOnLoad = DontdestroyOnLoadAccessor.Instance.GetAllRootsOfDontDestroyOnLoad();
    }
}
5 Likes

The method described above to get root game objects from the special “DontDestroyOnLoad” scene:

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.

1 Like

I use it in RuntimeInspector and it seems to work fine on 5.6 and later (don’t know about older versions).

Really clever, thank you

1 Like

Can you please explain how it works please?

1 Like

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

1 Like

Can you please tell me please where do I put this?

In the script that you want to access DontDestroyOnLoad objects from. Then you can call GetDontDestroyOnLoadObjects() function to get these objects.

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.

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