I just wanted to rant how much I hate the fact that the scene doesn’t have a true root element. It’s a forest instead (aka multi-root system), and to get to the top-level objects you have to do
SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects()
which is such a horrible thing that just breaks the recursive tree beauty apparently out of spite.
OP:
The actual hierarchy is encoded through transforms, not GameObjects, as explained above. It’s a bit weird, given that no GameObjects ever exist without a transform, but you’ll get used to it. I wouldn’t have a problem with it, if it wasn’t for the above. Unity is full of illogical design decisions like that. Iterative design by committee.
I mean don’t get me wrong, if you need to traverse the hierarchy trees, you’re probably doing something wrong(*), and that’s probably why no one seems to have an issue with the non-extant root object (don’t be fooled by Transform.root btw, that just gives you a topmost parent). I also didn’t need this ever until recently.
But if you need this then you have to do something like this
static public GameObject FindInScene(string path) {
if(string.IsNullOrEmpty(path)) throw new System.ArgumentException($"{nameof(path)} is empty or null");
// pops the first item
if(!path.SplitFromStart('/', out var name, out path)) { // returns false if '/' wasn't encountered
name = path;
path = null;
}
var rootObjs = getRootObjects();
foreach(var go in rootObjs) {
if(match(go.name, name)) {
if(string.IsNullOrEmpty(path)) return go;
var nested = go.transform.Find(path); // the rest of the path works as is
if(nested != null) return nested.gameObject;
}
}
return null;
static GameObject[] getRootObjects() => UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects();
static bool match(string a, string b) => System.String.Equals(a, b, System.StringComparison.InvariantCultureIgnoreCase);
}
I just find it crazy that it’s so complicated to have a fully qualified path to some object, and simply do this.transform.root.Get(path);
There should be a 1 to 1 between a scene and a root transform. I bet it would simplify things on their end as well. Or I dunno, call me spoiled.
Edit:
- The reason is why this is wrong is because it’s slow (especially when used on a hot path). There are half a dozen of smarter ways to latch onto an object in your scene without ever having to look for it via hierarchy, because you really want to store a direct reference to it in the runtime, instead of mulling the strings, producing garbage etc. If you must search for something, do it exactly once (i.e. in Awake) then store the result for later.
If you frequently access children or parents of an object (which isn’t bad per se, it’s commonly used), make sure to at least cache the OG transform locally, and work from there. And think of GameObjects just like Spiney suggested, as containers for components, they are literally just the main access point for all of the components (custom or otherwise), but usually not the main thing that you’re after.