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