Non Root-Level Portals

I am a bit of a stickler for having a tidy hierarchy. Portals at the root level doesn’t sit right with me. So, I had a bit of a thought about it and figured out a way I could have my portals as children of other game objects. I am sharing it here to get some feedback and maybe help some other ‘sticklers’ out a bit.

I ended up doing two solutions, the second evolved from the first. Note that I am only concerned with where the portals are at design time. They move around anyway, even without my solutions

First Solution

Grab the portal - wherever it may be - and add it to a root-level game object at runtime when we want to add the portal to DDoL and then add this root-level object to DDoL. For this, I made an extension method

public static class Extensions
{
    public static GameObject DontDestroyOnLoad(this GameObject obj)
    {
        // Create a game object in the hierarchy root
        var rootedParent = new GameObject($"{obj.name} (DDoL)");
        // Set the passed object's parent to this new game object
        obj.transform.SetParent(rootedParent.transform);
        // Add this new 'root-level' object to DDoL
        GameObject.DontDestroyOnLoad(rootedParent);
        // return the new object - we'll need it in the portals to destroy it
        return rootedParent;
    }
}

// In the Portal.cs
private IEnumerator Transition()
{
    if (sceneToLoad < 0)
    {
        Debug.LogError("Scene to load not set.");
        yield break;
    }

    // not this
    //DontDestroyOnLoad(gameObject);
    var ddol = gameObject.DontDestroyOnLoad();

    // .. snip ..

    // not this
    //Destroy(gameObject);
    Destroy(ddol);
}

So, this now allows me to have portals at any level in the hierarchy because at runtime we will move the portal to a root-level game object - when we want to persist the portal across scenes - and then add that game object to DDoL. We’re passing back that object because that’s the one we need to destroy now.

Second Solution

This is the same as the first solution, but instead of passing back the rooted game object, I pass back an IDisposable wrapper containing this game object. I can now enclose the code in a using clause and the portal (it’s parent, really) will be destroyed automatically when I am done

public static class Extensions
{
    public static IDisposable DontDestroyOnLoad(this GameObject obj)
    {
        // Create a game object in the hierarchy root
        var rootedParent = new GameObject($"{obj.name} (DDoL)");
        // Set the passed object's parent to this new game object
        obj.transform.SetParent(rootedParent.transform);
        // Add this new 'root-level' object to DDoL
        GameObject.DontDestroyOnLoad(rootedParent);
        // return the new object wrapped in a 'AutoDestroy' class
        return new AutoDestroy(rootedParent);
    }

    class AutoDestroy : IDisposable
    {
        private GameObject _parent;
        public AutoDestroy(GameObject parent) => _parent = parent;
        void IDisposable.Dispose() => GameObject.Destroy(_parent);
    }
}

// In the Portal.cs
private IEnumerator Transition()
{
    if (sceneToLoad < 0)
    {
        Debug.LogError("Scene to load not set.");
        yield break;
    }

    // not this
    //DontDestroyOnLoad(gameObject);
    using (gameObject.DontDestroyOnLoad())
    {
        // .. snip ..

        // not this
        //Destroy(gameObject);
    }
}

Now, the portal will be automatically destroyed as soon as the code execution leaves the using scope.


Again, I share this here to get some feedback regarding this

1 Like

I have a horrible secret to share, as I also dislike keeping Portals at the root level…

transform.parent = null;
DontDestroyOnLoad(gameObject);

If/when we rejigger the course, I can personally guarantee this will be in the lessons.

3 Likes

Ooof, so simple really, isn’t it…

It really is. I’ve been guilty of perpetuating the solution of ensuring that Portals are kept at the root level since I became the TA, but sometimes one line ONE LINE! can turn out to be the solution.

Privacy & Terms