- Home /
Finding the root GameObjects in the scene ?
Hi all, I'm wondering what could be the fastest way to find all the root game objects in the scene ? I currently use the FindSceneObjectsOfType( typeof(GameObject) ) and then taking the root gameobject but is there a faster way to do this ?
Thanks
PS I need this to reference the game objects added when I call the LoadLevelAdditive method.
Answer by DonKanallie · Jan 15, 2016 at 08:40 AM
With a recent Unity version (around 5.3) the preferred way would be
UnityEngine.SceneManagement.SceneManager.GetActiveScene().GetRootGameObjects()
[CO$$anonymous$$$$anonymous$$ENT EDITED] O$$anonymous$$, I thought that would only worked for objects saved in the scene but it actually works for unsaved scenes and when playing. It also handles multi-scene which is now activated by default and causes the solution with HierarchyProperty to return null elements (as thienhaflash spotted. Thanks!
this function doesn't work properly, it returns only one of the root game objects.
Answer by Adrian · Feb 25, 2014 at 06:34 PM
In the Unity editor (ONLY) ...
You can use following code to get all the root game objects directly (the same method is used internally by Unity in the hierarchy window):
public static IEnumerable<GameObject> SceneRoots()
{
var prop = new HierarchyProperty(HierarchyType.GameObjects);
var expanded = new int[0];
while (prop.Next(expanded)) {
yield return prop.pptrValue as GameObject;
}
}
You can use this method with foreach
or query it further using Linq:
foreach (var root in SceneRoots()) {
Debug.Log(root);
}
SceneRoots().Select(g => g.transform).ToList();
And as a bonus, a method to iterate over all scene objects breath-first:
public static IEnumerable<Transform> AllSceneObjects()
{
var queue = new Queue<Transform>();
foreach (var root in SceneRoots()) {
var tf = root.transform;
yield return tf;
queue.Enqueue(tf);
}
while (queue.Count > 0) {
foreach (Transform child in queue.Dequeue()) {
yield return child;
queue.Enqueue(child);
}
}
}
Seems to be the most promising answer so far. I will check to see if it works. FindObjectOfTypeAll will works, too, but maybe it's bad for performance.
fyi, this script is not suitable for mobile dev, i've tried a 'build to android' and it complains it cant find the unity editor package or something, asked a question about it.
@ninjanoel, this code is only intended for editor use, as the author stated ("In the editor ...")
Very nice, I would call this the correct answer for editor usage. (Not for runtime obviously.)
Note that you can use this approach to find objects at edit time, then tag them (from code), and at runtime search by tag, which is fairly efficient.
Answer by yoyo · Dec 30, 2010 at 11:55 PM
You can find a single root object like this (C#):
Transform xform = UnityEngine.Object.FindObjectOfType<Transform>();
GameObject rootObject = xform.root.gameObject;
Note that this calls FindObjectOfType rather than FindObjectsOfType, so it's faster [EDIT: Or so you would expect, however FindObjectOfType actually calls FindObjectsOfType behind the scenes, so it's actually just as slow]. However if your scene has more than one root object it will only find one of them.
So ... anyone know how to find all the root objects efficiently?
This works, but uses FindObjectsOfType, which the docs warn is slow, plus it needs to allocate an array big enough to hold all the transforms in the scene. I would like to know if there's a better way:
List<GameObject> rootObjects = new List<GameObject>();
foreach (Transform xform in UnityEngine.Object.FindObjectsOfType<Transform>())
{
if (xform.parent == null)
{
rootObjects.Add(xform.gameObject);
}
}
Answer by BinaryCore · Sep 20, 2010 at 08:51 PM
Another way is that you could also use Tags to tag your root game objects with a distinct tag type like "RootGameObject" and then use GameObject.FindGameObjectsWithTag("RootGameObject") to get all the root types.
A nicer way would be to be able to check a GameObject to see if it is a child of any other GameObject, like a GetParent() call. If that is null, then it's a root object. But, using the t.parent on the transform as he described above should do the trick too.
It's a good idea, but requires diligence in correctly tagging your root objects.
In the end I used the editor-only method from the other answer to quickly find the roots at edit time, and automatically tag them so they can be found efficiently at runtime.
This is the fastest method to do that in my case (<5ms) vs UnityEngine.Scene$$anonymous$$anagement.Scene$$anonymous$$anager.GetActiveScene().GetRootGameObjects() (>6ms) vs FindObjectsOfType(); (>12ms) Anyway, i don't use tags for anything else.
Answer by Mike 3 · Sep 20, 2010 at 01:19 PM
I'd do it via Transform instead of GameObject, but otherwise no, that'll be pretty much the fastest way
If you use Transform instead of GameObject, you can just check if t.parent is null, if so it's the root (plus you don't have to get go.transform for every object)