Search Unity

GameObject.Find() vs transform.Find() vs transform.FindChild()

Discussion in 'Scripting' started by Wutai, Oct 29, 2013.

  1. Wutai

    Wutai

    Joined:
    Apr 21, 2013
    Posts:
    2
    Hi :)

    I just want to check to see if I understand Find()

    GameObject.Find("myObject") will search the scene for an object called myObject.
    transform.Find("myObject") will only search the game objects children for an object called myObject.
    transform.FindChild("myObject") is the same as transform.Find()

    thanks..
     
  2. supermunkey

    supermunkey

    Joined:
    Feb 4, 2013
    Posts:
    24
    I can confirm that GameObject.Find ("myObject") will indeed search the scene for an object called myObject.
    The others I am not sure about , I know my input is not exactly great but this is the first time a post has come up and I have at least been able to answer some of it :p. (unity newb)
     
  3. DanielQuick

    DanielQuick

    Joined:
    Dec 31, 2010
    Posts:
    3,137
    You are correct about transform.Find.

    There is no such thing as transform.FindChild. You may be confusing it with transform.GetChild which is similar to Find, but searches by an integer index rather than a string.

    Also note that GameObject.Find returns a GameObject, while transform.Find returns a Transform.
     
  4. KyleStaves

    KyleStaves

    Joined:
    Nov 4, 2009
    Posts:
    821
    Transform.FindChild() is no longer part of the documentation, but still exists as part of the UnityEngine assembly. It is depreciated and is functionally identical to Transform.Find().
     
  5. jankrib

    jankrib

    Joined:
    Dec 17, 2012
    Posts:
    12
    It also seems that GameObject.Find only finds active game objects, while Transform.Find will find the transform even if the game object is inactive.
     
    raklear, roddles and Westland like this.
  6. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    AndrewGrayGames, Westland and ptr0x like this.
  7. mattparkins

    mattparkins

    Joined:
    Apr 1, 2014
    Posts:
    31
    Not really "at all costs" - it is perfectly acceptable to use it in start() & awake(), and in some instances it is unavoidable.
     
  8. Cawas

    Cawas

    Joined:
    Jan 14, 2010
    Posts:
    121
    Even in `start` and `awake` it can be abused and should still be avoided.

    I'm in fact failing in thinking of a good usage for `Find`, although I'm almost positive there must be one...
     
    SirNiklas likes this.
  9. mattparkins

    mattparkins

    Joined:
    Apr 1, 2014
    Posts:
    31
    Anything can be abused. But anyway...

    For me I built a 2D composite object in the editor and needed the parent to talk to one of the children, so I use transform.find in start() and store the returned reference for use in Update(). If there is a better way of building composite objects that need to talk to particular kids then I'd adopt it, sure.
     
  10. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,338
    The child will probably have a script on it (since you'll need to "talk" with it), so you can do GetComponentInChildren. If there's several children with the same type, you can create a public field and assign it in the inspector.

    GameObject.Find is the worst. It's slow, it creates garbage (the string you create), you don't get any errors if it fails, and you don't get any errors if there's more than one object with the same name and which one you're trying to reference is ambiguous.
     
  11. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    What do you think of having a singleton class called 'references' that is nothing but a way for objects to add themselves to it? In a gameobject's start function, you can just add it to a list of whatever it is in the references singleton :D
     
    image28 likes this.
  12. zenGarden

    zenGarden

    Joined:
    Mar 30, 2013
    Posts:
    4,538
    Should Find and FindChild still be avoided ? Why are they still part of the framework ?
     
  13. Tomnnn

    Tomnnn

    Joined:
    May 23, 2013
    Posts:
    4,148
    It's probably an accessibility thing. They're horrible but easy to use for newbies.
     
  14. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    try to avoid find things by string names, it is bad practice to hard code that S***, when you can just make a SerializedField in the inspector and drag in the reference you need.
     
    image28 likes this.
  15. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    It's been a while, but I just had to deal with this problem in a little project I'm tinkering with. I wrote up a neat little extension method to address it:

    Code (csharp):
    1. /// <summary>
    2. /// Performs a depth-first search of the transforms associated to the given transform, in search
    3. /// of a descendant with the given name.  Avoid using this method on a frame-by-frame basis, as
    4. /// it is recursive and quite capable of being slow!
    5. /// </summary>
    6. /// <param name="searchTransform">Transform to search within</param>
    7. /// <param name="descendantName">Name of the descendant to find</param>
    8. /// <returns>Descendant transform if found, otherwise null.</returns>
    9. public static Transform FindDescendentTransform(this Transform searchTransform, string descendantName)
    10. {
    11.     Transform result = null;
    12.  
    13.     int childCount = searchTransform.childCount;
    14.     for (int i = 0; i < childCount; i++)
    15.     {
    16.         Transform childTransform = searchTransform.GetChild(i);
    17.  
    18.         // Not it, but has children? Search the children.
    19.         if (childTransform.name != descendantName
    20.            && childTransform.childCount > 0)
    21.         {
    22.             Transform grandchildTransform = FindDescendentTransform(childTransform, descendantName);
    23.             if (grandchildTransform == null)
    24.                 continue;
    25.  
    26.             result = grandchildTransform;
    27.             break;
    28.         }
    29.         // Not it, but has no children?  Go on to the next sibling.
    30.         else if (childTransform.name != descendantName
    31.                 && childTransform.childCount == 0)
    32.         {
    33.             continue;
    34.         }
    35.  
    36.         // Found it.
    37.         result = childTransform;
    38.         break;
    39.     }
    40.  
    41.     return result;
    42. }
     
    Mr-Logan and zenGarden like this.
  16. image28

    image28

    Joined:
    Jul 17, 2013
    Posts:
    457
    This is how I do it.
     
    AndrewGrayGames likes this.
  17. AndrewGrayGames

    AndrewGrayGames

    Joined:
    Nov 19, 2009
    Posts:
    3,821
    I usually avoid Singletons in the classic sense. I have a type of object called a 'Manager' which is similar, in that it exposes an 'Instance' property, and is usually hosted on a DontDestroyOnLoad object. I like a "Manager" pattern a little better, because Singletons get into messy places with thread-safety and, at least in Unity, may or may not persist state between scene transitions. My Manager pattern doesn't have either of those problems!
     
  18. image28

    image28

    Joined:
    Jul 17, 2013
    Posts:
    457
    Ah, Mine are for single scene use only
     
  19. Shyzen

    Shyzen

    Joined:
    Aug 17, 2013
    Posts:
    1
    It's been a while but here is more information on good practice while making a search.

    For anyone wanted a deep search, please question the breadth-first or deep-first aproch on the (Rect)Transform's tree.

    Deep-first as stated above will look all the subchild before going to next sibling while breadth-first will begin by scanning all child then for all child scanned, it scan their child and so on. Depending on your hierarchy, it could be a good practice to question that to increase search speed. And better, ban all search at maximum...

    You could find both here : http://answers.unity3d.com/answers/799493/view.html

    FindChild is still not stated as deprecated.
     
  20. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    I understand that this is an old thread but I still think it's important to clarify this: There is no such thing as something that should be avoided "at all cost" in game development (or, to be a little more general, in life). So no:
    Find(string)
    and
    FindChild(string)
    should not be avoided!

    Instead, you need to understand what these methods do, and what that means when using them:

    GameObject.Find(string)
    searches the whole scene hierarchy and returns the first game object that exactly matches the name.

    So, the two obvious implications are:
    1. A call to
      Find(string)
      has a significant performance impact that increases the more objects you have in your scene, and
    2. the result depends on the naming in your hierarchy.
    The performance impact means you should not call this in performance critical code-paths, especially not in large scenes ("large" in the sense of "many game objects"). That the result depends on the naming in your hierarchy means you should only use this method if you really want a GameObject that has a specific name. Even a typo could break it. And if there are multiple game objects that have the name that you look for, you won't know which one you're getting. But this may be exactly what you want, e.g. if there are several objects by that name and you just want any of them.

    So, if you're working on a larger project, and/or in a team, or you create something that other people may use (e.g. a package for the Asset Store), you'll usually want to use approaches to find your objects that are more reliable, faster, and don't impose a naming scheme to the project.

    But, just to give one random example, if you know that a game object is procedurally created during runtime, with a specific, reliable name, and it's not properly assigned in the scene hierarchy, but you need it, as a fallback, you could use
    GameObject.Find(string)
    to check if it's in the scene at all, anywhere, and maybe just not properly assigned. In that case, you'd probably log a warning or error, and if the find fails, you might instantiate the object you need, assign it properly and go on with your business. Of course this would have a performance impact and maybe even cause a noticeable hiccup - but that's better than the game completely falling apart.

    Because sometimes, you don't care about performance, and sometimes, you only care about finding an object with a specific name. Also, you might have a scene with only very few objects - in that case, the performance impact doesn't even matter much.
     
  21. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    That's absolutely not true. There is such a thing as doing something wrong - implementing something in an objectively bad way. And if something is implemented in a bad way, you should avoid using that thing.

    I have never, in 13 years of professional Unity experience, I have never found a situation where GameObject.Find was either necessary or the best way to find a reference to an object in runtime, nor have I heard of such a situation described by anyone else. I posit that, if you think you have, you most likely just didn't know all the possible alternatives. GameObject.Find is occasionally useful in editor or debug code, but never for anything a user will run.

    And it's not only about performance, either - it's a reliability issue. It's too hard to know whether the object's name might change when you update another component, whether a second object with the same name might come into existence, whether some bit of code you might only run 1 in 1000 plays could have a typo that went unnoticed because it would create a runtime error and not a compiler one - just too many unknowns.

    If that's your example, it's a bad one. If you know that a game object is created "with a specific, reliable name", you can store a reference to that object when it was created and use that reference. If it was "not properly assigned", then there is an unexplained bug in the code and the object itself will not be in a reliably good state - better to fix that bug than to put a bandaid over it.
     
    mowax74 and Suddoha like this.
  22. DonLoquacious

    DonLoquacious

    Joined:
    Feb 24, 2013
    Posts:
    1,667
    I tend to agree with StarManta's stance more on this, though yeah, there are no absolutes. A tool is a tool, and if you look hard enough and long enough, you'll find some good use for a crowbar shaped like a figure-8. Find and FindChild are pretty awful though, and the only legitimate (IMO) reason I've ever seen for using them are for super-quick tests/demonstrations, debugging, and as a "last resort" backup option for resolving lost references in very specific circumstances where the naming convention can be counted on being consistent.

    I also think that learning how these are poor options, and learning/creating better alternatives, is probably one of my favourite beginner-level lessons to see people taking on in Unity. I don't think the functions should be removed, at all, and I think these arguments about their effectiveness are, on the whole, good things to have here and expose people to. Better solutions always exist for this, but no one solution that works for every situation. Figure out the one that works for your use-case, and if you honestly can't find one, recognize that you should probably be studying up on programming or redesigning things so that one is available, because it points to bigger issues.
     
    jashan likes this.
  23. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    I fully agree with you on that! Of course there are objectively bad ways of doing something, and things to be avoided.

    My posting, however, was addressing the idea of "avoiding something at all cost". In other words, about following some sort of dogma without understanding the rationale of why you should or should not use something in given circumstances.

    The posting that I directly replied to also had "Why are they [methods like GameObject.Find()] still part of the framework ?" and my answer implicitly addressed that part, even though I didn't include it in my quote. So maybe I removed too much context (I picked up the "avoid at all cost" from an earlier posting in this thread that I also haven't quoted explicitly). Also, I'll admit that I personally have never used
    GameObject.Find(...)
    , so I'm probably not the best person to come up with examples. The first use-case that popped up in my mind was an editor script that does a search in the hierarchy - but there already is a search-field for that, so I tried to come up with something more plausible. I do see
    GameObject.Find(...)
    sometimes used in singleton-implementations in various projects / packages. But that would rather be a great example of where not to use this. That said, while the method is used in there, it's usually never actually called but just a fallback, so it's not as bad as it sounds and in a way similar to my example but in important ways very different. There's an argument to be had about advantages and disadvantages of throwing exceptions, logging errors, or silently failing with a fallback - but this posting already is quite long.

    Maybe my point is easier to make with foreach-loops, coroutines and allocations / garbage collection:

    A few years ago, I have replaced almost all foreach-loops with for-loops in one project, and also all coroutines with a zero-allocation approach. It did that even though it cost a lot of my time and make the code less readable (the coroutines-replacement was non-trivial and also caused a bunch of fairly nasty bugs). I usually favor readability / maintainability and stability / robustness over performance, unless the performance impact is significant ("significant", in this context, of course, by realtime standards). In this case, I needed zero-allocations, and at that time, foreach-loops did allocate a few bytes and that did add up, resulting in framedrops in a VR project that could create unfair situations, besides the obvious comfort issue caused by framedrops in VR.

    I have read recently that the foreach-allocations have been fixed but didn't have time to confirm this with a test, yet, because there are other things with higher priority on my table. If this was actually fixed, the best thing would be to revert those changes; except the time spent doing that might be better used doing things that not only improve the code-style. Also, with incremental garbage collection now available, I probably wouldn't have to take it to that extreme today. JetBrains Rider has a nice refactoring that would have saved some of my time and will save time in case I ever decide to revert to foreach. It's kind of funny to get all these IDE-warnings now, asking me to change it back to foreach, knowing that at the time I made that change, it was the objectively better way of writing those loops ;-)

    To give another, more related example: For debugging-convenience in the editor, I will sometimes make sure that objects that are instantiated during runtime will have useful names, which often means quite a bit of
    string.Format(...)
    , or now
    $"..."
    , and sometimes objects being renamed several times during their life-cycle. From a pure performance perspective, that's insanity. But it can make development more efficient and that is often more important that performance of the game running in the editor.

    Obviously, these operations are never compiled into actual builds.

    It can be "the best way" in circumstances where you want to "quickly" find an object by name from script. With "quickly", I'm obviously not talking about performance but about situations where even thinking about performance, or "how to do it in the best possible way" would be a waste of your time. Like:

    ... but if you avoid
    GameObject.Find()
    at all cost, you couldn't use it in those cases. Instead, you'd waste your time writing something more specific and efficient ;-)

    TL;DR: It's all about knowing what you're doing and weighing out things from all relevant perspectives. Sometimes, you should spend as much time as needed to find the optimal solution from a performance perspective. Sometimes, a quick and dirty solution like
    GameObject.Find(...)
    is the optimal solution from the perspective of development time. And sometimes, I spend way too much time on philosophical rants ;-)
     
  24. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    The irony is that I found this thread looking for a way to quickly find objects that contain specific substrings in their name in a sub-hierarchy (this is for automatically mapping a hand-rig that might come from an unknown source, with unknown naming conventions). So I have arrays with the most likely name-parts that I iterate over while removing every bone-type that I have already found from the list. The only thing I can rely on in this case is that the gameobjects are there, and when there is a naming convention that doesn't match, I have to add it. There probably are also heuristics that use the poses of the bones for more reliable results ... but ... you have to stop somewhere ;-)
     
  25. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    so then, how about Transform.Find? performance.
     
  26. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    It still uses Object.name, which is expensive (while that looks like a simple string member variable, it's actually a property that does quite a bit behind the scenes, including allocating memory), so I would use it with caution. That said, it only looks at the children of the transform that you're calling it on, so it's fairly predictable. Also, it does support path notation, so that's also cool.

    In general, with anything performance-related, you should always think about "does it even matter" first (like, in the example I gave above, as it's an editor script only called occasionally during authoring), performance would only matter if that call took minutes. If, on the other hand, you are working on something that is called every frame, all the time, while players are playing the game, you should definitely profile and consider possibilities for optimizations.

    So, if it's code that matters, I would also profile and look at both, the time it takes and the memory it allocates. If it allocates memory, that alone can be a problem.
     
  27. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    but just few dozen lines of transform.find is ok? if just call at Start or Awake for get reference from prefab instantiated.
     
  28. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    In Awake() and Start(), it should be fine. One thing to consider: Setting up references via name can break quite easily. Personally, I always have a component at the prefab root which has all relevant references properly wired up / serialized, so I can hook things up in a reliable way during runtime.
     
  29. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    yes you mean using only exception that public variable referencing allowed only to its own children objects, surviving even after become prefab?
     
  30. jashan

    jashan

    Joined:
    Mar 9, 2007
    Posts:
    3,307
    If I understand your question correctly, then yeah. Obviously, you can't serialize scene references into a prefab. But what you can do is have a component on the prefab root that has any relevant references. Then, when you instantiate the prefab, you take that root component and hook it up with whatever you need.

    Generally speaking, it's a good idea to spend some time thinking about how you set up your scenes and prefabs. There are a lot of things that may look convenient at first but when you go down that route, you'll end up in a terrible mess. My favorite example are serialized event handlers: You do need them when components are not supposed to know about each other. And sometimes, you may want to be able to have a level designer hook up things, so yeah, serialized event handlers are absolutely useful. But doing the setup in the scene via serialized event handlers also has quite a few disadvantages so I'd only use them in the specific cases where it's the only option. Usually, it's much better to have a reference to the component that has the event handler, and then set up things from code (either in Awake() or OnEnable() / OnDisable(), with OnDisable() obviously de-registering ... in rare cases, Start() may be better than Awake()).

    But with serialized object references, it's usually the opposite: Doing dynamic lookups from code during runtime is sometimes necessary (e.g. in certain modding scenarios where things are extremely loosely coupled). Usually, you'll want things properly hooked up during deserialization (i.e. when the objects are instantiated, e.g. when the scene is being loaded).
     
    TigerHix and jjc6252498 like this.