As far as I can tell, transform.Find("name") is supposed to look through the hierarchy of the object the script is attached to and return the transform of the first object named "name" that it finds. But it just doesn't. I get null back. Using gameObject.Find looks through the whole scene, but I need to wire together the hierarchy under a particular object. What am I missing?
Aha... I thought the Find would be recursive the same way GetComponentInChildren is, but it only searches the one level of children... Do I have to roll my own recursive search, or is there a better way? I want the transform of a gameobject with a particular name.
If your objects will all have unique names then it seems GameObject.Find would world well enough for you. Otherwise if you're specifically after a child object of that name then you'll have to roll your own recursive transform.Find routine.
In my case I did have to do the search myself (fortunately really simple.) I was just thrown by the different behaviors of the Find- and Get-type functions. GameObject.Find will search the whole scene (recursively), I kind of expected gameObject.Find to search just the object hierarchy the script is attached to. (Any reason it shouldn't?) And of course the GetComponentInChildren procedures go deeper than one level. Personally, I think it could be more consistent, but I guess it's too late to change the API .
This is a shame. Surely there is a demand for such a function. I need to find a bone on a verbosely named and long skeleton and would much rather do transform.FindChildRecursively("Head") than give a 5 deep path!
I use the following myself, but haven't tested it thoroughly: Code (csharp): using System.Linq; using UnityEngine; public static class Helper { public static GameObject FindInChildren(this GameObject go, string name) { return (from x in go.GetComponentsInChildren<Transform>() where x.gameObject.name == name select x.gameObject).First(); } } Used like so: Code (csharp): ... var cheese = gameObject.FindInChildren("Cheese"); ...
That works so well, npsf3000. How do you think to use all these weird operators, like "from / where / select"? I've never seen them used before.
As Kyle said Linq. It's one of the many awesome features of C#/.NET that are there for the taking Another one is helper methods, also demonstrated in that example! The great thing about Linq is that even if you've bever seen those keywords before - it should be very easy to follow the logic and write the following instead: Code (csharp): using System.Linq; using UnityEngine; public static class Helper { public static GameObject FindInChildren(this GameObject go, string name) { foreach (x in go.GetComponentsInChildren<Transform>()) if (x.gameObject.name == name) return x.gameObject; throw new System.Exception ("Technically the old version throws an exception if none are found, so I'll do the same here!"); } } Bonus points - see how many of these you are familiar with.
Although in this case there's really nothing gained (in readability, performance, etc) over a foreach
Here's an option if for whatever reason you can't or don't want to use linq Code (CSharp): public static GameObject FindInChildren(GameObject gameObject, string name) { foreach(Transform t in gameObject.GetComponentsInChildren<Transform>()) { if(t.name == name) return t.gameObject; } return null; }
Without the garbage overhead of foreach and GameObject.GetComponentsInChildren: Code (csharp): public static Transform FindInChildren(Transform transform, string name) { if(transform == null) return null; int count = transform.childCount; for(int i = 0; i < count; i++) { Transform child = transform.GetChild(i); if(child.name == name) return child; Transform subChild = FindInChildren(child, name); if(subChild != null) return subChild; } return null; } public static GameObject FindInChildren(GameObject gameObject, string name) { if(gameObject == null) return null; Transform transform = gameObject.transform; Transform child = FindInChildren(transform, name); return child != null ? child.gameObject : null; } As extension methods: Code (csharp): public static class ExtensionMethods { public static Transform FindInChildren(this Transform self, string name) { int count = self.childCount; for(int i = 0; i < count; i++) { Transform child = self.GetChild(i); if(child.name == name) return child; Transform subChild = child.FindInChildren(name); if(subChild != null) return subChild; } return null; } public static GameObject FindInChildren(this GameObject self, string name) { Transform transform = self.transform; Transform child = transform.FindInChildren(name); return child != null ? child.gameObject : null; } } // Usage: // transform.FindInChildren("Name"); // gameObject.FindInChildren("Name");
All these methods are not very good because Object.name cause managed string allocations and also has some P/Invoke overhead. I think Unity developers should create a built-in solution.