Let’s start by showing what I would expect from a modern environment that has .NET 4.6. compatibility. Suppose you created this hierarchy:
To get access to the GameObjects in the hierarchy tree, you want to be able to do something like:
private Transform _handle;
private Transform _bottom;
void Start()
{
_handle = this.transform.FirstChildOrDefault(x => x.name == "handle");
_bottom = this.transform.FirstChildOrDefault(x => x.transform.localScale.y == .1f);
}
In Unity, the following options are supported for finding the first instance of a GameObject or Transform:
Method | Description | Recursive | Returns |
GameObject.Find | Finds by name | No (but supports paths like a/b/c) | GameObject or null |
GameObject.FindGameObjectWithTag | Finds by tag | No | GameObject or throws Exception |
GameObject.FindWithTag | Finds by tag | No | GameObject or throws Exception |
myTransform.Find | Finds by name | No (but supports paths like a/b/c) | Transform or null |
The provided methods only provide finding by name or tag and if you change your hierarchy, searching by path a/b/c
might break. What we want is one function that will search your object tree and allows you to find the first object that satisfies your search query. This can be achieved by creating an Extension Method that takes a parent Transform and predicate to recursively search your hierarchy.
The following FirstChildOrDefault
method returns the first Transform in your object hierarchy that satisfies predicates like x => x.name == "deeply_nested_cube"
Update 2019-10-04. There is an improved version of this code. You can find it at Find GameObject recursively in the Unity hierarchy with LINQ queries
Here is the code. Just add it to your project:
using System;
using UnityEngine;
public static class TransformEx
{
public static Transform FirstChildOrDefault(this Transform parent, Func<Transform, bool> query)
{
if (parent.childCount == 0)
{
return null;
}
Transform result = null;
for (int i = 0; i < parent.childCount; i++)
{
var child = parent.GetChild(i);
if (query(child))
{
return child;
}
result = FirstChildOrDefault(child, query);
}
return result;
}
}
Suppose you have a scene with a cube deeply nested in the hierarchy like this:
You can now use FirstChildOrDefault to get a reference to that cube. NestedTest
is a MonoBehaviour attached to empty GameObject a
in the hierarchy:
And the code looks like this:
using UnityEngine;
public class NestedTest : MonoBehaviour
{
void Start()
{
var cube = this.transform.FirstChildOrDefault(x => x.name == "deeply_nested_cube");
Debug.Log(cube);
}
}
Look at the result in the console:
Now you have a tool to get access to all Transforms in the hierarchy by using lambda expressions.
Some developers claim that finding elements in the hierarchy is slow. But speed is relative here. It all depends on these things:
void Start()
or in a game loop like void Update()
?In all cases, performance depends on the amount of items in the hierarchy and Whether you use recursion or not. Claiming a certain method (like Find or GetComponent<T>) is slow only makes sense when you know how many objects you are dealing with.
Find, FindWithTag and GetComponent<T> are no magic functions. They go through a list of objects and try to match items. So keep in mind:
void Update()
adds another complexity of O(n).I hope the FirstChildOrDefault
extension method will save you a lot of work when you are trying to find objects in the hierarchy.