Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

GameObject.Find(...)

Discussion in 'Scripting' started by boylesg, May 25, 2016.

  1. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I have noted many people saying that this function is inefficient and to minimize calls to it.....yada yada yada.

    So is their likely to be any significant gain, re efficiency, to build a binary tree of game objects at start up and implement a custom Find(...) function that traverses such a tree?

    Or would folks regard the gains to be not worth the effort?
     
  2. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    If in doubt profile.

    But it really depends on why you need to keep using Find
     
  3. techmage

    techmage

    Joined:
    Oct 31, 2009
    Posts:
    2,133
    this was wrong
     
    Last edited: Mar 31, 2021
    ZoroSrk, Ziplock9000 and Kiwasi like this.
  4. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    no
     
    MaikelJ likes this.
  5. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I am actually using GameObject.Find(...) in void Update(), but in response to user input rather than just running constantly. And I am using it only when I can't do transform.parent.gameObject.SendMessage(...) due to my gameobject hierarchy .

    So it sounds as though, in this scenario, I am fine using it in Update().
     
  6. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Actually, I came up with a MFC message map like system for communicating between modules with unique int message IDs.

    I started of doing the standard SendMessage("FuncName", object") thing but I quickly recognized that this was going to degenerate into spaghetti code.

    I am still using SendMessage("FuncName", object")but my base class is routing the messages through a single overridable function that all script have by inheriting my base class.

    protected override void DoReceiveMessage(Parameters p)
    {
    base.DoReceiveMessage(p);
    if (p.m_nMsgID == MessageIDEnum.MSGID_BUTTON_CLICK)
    {
    string strSendName = (string)p.m_objParam1)
    .
    .
    .
    }
    else if (...)
    {
    }
    }

    So at least you only have to look for one single function in all scripts to get an idea of its major functionality.
     
  7. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    The greater problem with relying on Find is the fact you have to ensure everything has a unique name. I've yet to figure out where I need find beyond simple setup for artist convenience - ie I've never actually found a use for it in gameplay (nor would I consider it reliable).
     
    Mycroft and Kiwasi like this.
  8. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I am using Find(...) and SendMessage(...) as a generic means to invoke functions in scripts without having to instantiate my specific script.

    As in MyScript s = GetComponent<MyScript>();

    This method of invoking functions in your scripts completely breaks the whole inheritance/polymorphism paradigm of object oriented programming. There is no way you can push common functions back into a generic base class that can be re-used in different apps.

    If it was implemented in Unity something like the following then it would be fine.

    Script s = GetComponent<Script>();

    Since the editor already stores the name of a cs file if you add one to a game object, it shouldn't be all that difficult figuring out what functions and classes are available in the generic Script object.
     
    Last edited: May 25, 2016
  9. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Surely it is not that difficult if the name you give a game object reflects its purpose or function plus numbering if more than one is needed.
     
    Ziplock9000 likes this.
  10. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    But why when you can drag in your reference or get it via a other means. More can go wrong when trying find objects via string. Just seems your fighting the system when their are better solutions to this problem.
     
    Mycroft likes this.
  11. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    He is right. As a rule string based programming is evil. You are giving up all of the comforts of a modern compiler and racing out on your own. Both Find and SendMessage are prone to this problem.
     
    Mycroft likes this.
  12. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I did start doing that at first. But even with a Bingo Game with 75 balls, dragging and dropping that number of objects is a bloody pain in the ar$e.

    And then if you happen to want to change the name of your script for what ever reason.......

    Bugger that - I would rather use Find(...) and do away with the drag and drop links.

    And again NOT having drag and drop game object links is more amendable to inheritance and polymorphism.
     
  13. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Uniquely naming them for find to work is also a pain. ;)

    A couple of approaches of used to do the same thing.
    • Instantiate the objects at runtime. Keep the references.
    • Set up the objects as children of a single parent. Grab the references by iterating through children.
    • Have the objects register themselves with a manager in Start.
    Your way works too. Just putting out some options to consider.
     
    Mycroft and Munchy2007 like this.
  14. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I don't really agree! What is so evil about string based programming? The Unity editor is full of strings after all!

    Besides, the WHOLE point of object oriented programming is the create RE_USEABLE code elements through inheritance and polymorphism.

    At least that is what Latrobe University (Victoria, Australia) taught me.

    To my way of thinking the general Unity way of coding is going against the intent of object oriented programming in general. So I am merely finding ways to adapt Unity to take as advantage of C# inheritance etc as far as is possible.

    I see little point in re-writing the exact same code in 100s of different scripts and having to alter 100s of separate script if I want to make an identical change in all of them. Better by far to have them all inherit a base class and make the code change in ONE script.

    An example in my Bingo3D app....

    BaseButton -->BasePush Button
    |
    --> BaseToggle Button

    Both the latter have three possible states: 'pushed', 'not pushed' and 'disabled'.

    This is accomplished by supplying the derived button classes with three sprites corresponding to the three states.
    The basic functions of enabling/disabling, pressing and unpressing etc is done in BaseButton - it is identical for both button types.

    BasePushButton and sets a pressed state briefly and then return to an unpressed state in response to user input. BaseToggleButton sets the opposite state and retains it upon user input. Then actual scripts I attach directly to game objects do not much more than supply the specific sprites. This is what object oriented programming is supposed to be all about.

    I cannot see any advantage to having two separate PushButton and ToggleButton scripts, that I attach to actual game objects, and that contain identical segments of code. That is not proper object oriented programming based on what I was formally taught.
     
    Ziplock9000 likes this.
  15. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    I think you need to look at your approach, since I can assure you their are much better ways than having to search for or assign that many references
     
  16. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Horses for course I suppose - I don't have any problem with naming objects and scripts uniquely......at least not so far.

    I find it FAR more irritating (and slow) having to repeat identical code segments in multiple scripts.
     
    Ziplock9000 likes this.
  17. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    Not repeating code in scripts seems like a good solution. you can reuse components and components can use inheritance and interfaces.
     
  18. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Look in all the years I have been programming in a respectable variety of different platforms, I have not come across a better naming convention (for classes, data members, functions,.....) than the one generally used in Microsoft Foundation Classes for Visual C++.

    So I try to broadly stick to that sort of naming convention in my Unity scripts, game objects, sprites, Arduino sketches, PHP and javascript,......

    And I rarely run into the problem of running out of unique names.
     
    Ziplock9000 likes this.
  19. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294

    Why does people keep assuming this?

    I've seen the same said about FindObjectsWithTag too. Both of the operations are linear. They do a search of all your objects. They're O(n) operations where n=number of objects in the scene.

    If you actually check (Like I just did, again, just to be safe), increasing the number of objects in the scene increases the amount of time it takes for GameObject.Find to run. It's still fast (0.03 seconds with 200k objects on my computer), but it's not constant time. Note that the earlier the object is in the hierarchy, the faster it's found (so ~0 seconds with 200k objects if the object is the first), so the implementation is probably dead simple.

    Both the misconception about FindWithTag and Find must build on some idea that Unity has a cache of names it maintains behind the scenes and uses for the lookups. There's no such thing.


    EDIT: And to the discussion that sprang up: don't base your code around there being specific strings in the scene. That breaks all and any chance of reusability, and misspellings can and will be your doom.
     
    Kiwasi and Mycroft like this.
  20. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    I have fiddled around with these a little but I am not clear how they address identical code segments that are repeated in multiple scripts. I don't see how interfaces can address identical code segments in my button classes outlined above for example.
     
  21. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well then that could easily be addressed....

    • Universal base class for ALL script classes.
    • Static binary tree data member in this universal base class.
    • Each script adds its game object to the tree in Start() or Awake().....not sure if some sort of semaphore is needed, depends on threading in Unity.
    • Universal base class implements a Find(...) function that searches the binary tree rather than using GameObject.Find(...)
    • QED
    That is an improvement on O(n).
     
  22. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    So do it.
     
    Kiwasi likes this.
  23. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    That was the purpose of my original post - were the efficiency gains worth the effort.

    Probably not for my current Bingo app but, from posts in here, quite possibly for significantly larger apps were O(n) might become more of an issue....
     
  24. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    I believe that managing that tree - you'd have to remove objects in their OnDestroy - would cost a lot more than doing some GameObject.Find calls.

    If you have an actual problem (That you have found. While profiling.) where a lot of calls to GameObject.Find is causing performance issue, the solution is not to improve GameObject.Find, but to cache the results of whatever you're finding.

    The game loop (and everything that's touched by UnityEngine) runs on a single, main thread. The underlying c++ engine does a bunch of multithreaded stuff, but the don't have to worry about locks for gameobjects.
     
    Kiwasi and Mycroft like this.
  25. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160
    The issue is GameObjects.
    When working in a team, it's almost impossible to maintain code based around searching for names. (I worked on 3 major games that used this type of system: Spider-Man 2, Doom 3 and X-men Legends 2.)

    Any time a person changes the name of a GameObject, you have to change your script. That's not *too* bad with one person in a file, but that's not reality. Artists, lighters, programmers, level design, scripters, etc all have reasons for renaming GameObjects and it always ends up in broken levels/scripts.

    It's a poor decision to make *especially* when Unity/C# makes it trivial to avoid the issue.
     
    Kiwasi and Ryiah like this.
  26. Flaring-Afro

    Flaring-Afro

    Joined:
    Jul 20, 2015
    Posts:
    14
    Shouldn't this never be called in Awake? I thought Awake happened as soon as an object was created and therefore the object you are looking for may not exist yet.
     
  27. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,952
    Have you researched into automating the process via an editor extension?

    If you do you'll run into one of the many reasons why hardcoding strings aren't any better.
     
    Mycroft likes this.
  28. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Awake is called after all the objects are created, but before the objects are initialized. So setting up references is legit. Using references is not.
     
    Ryiah, Flaring-Afro and Mycroft like this.
  29. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Find and replace in Monodevelop is your friend in situations like that.

    I can edit a large number of calls to Resource.Load(...) and such like great deal quicker than I can drag and drop stuff in the editor.
     
    Ryiah likes this.
  30. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,952
    It's still an extra step you have to remember to do whereas Unity's editor will seamlessly handle renames for the inspector.
     
  31. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    You have to give your gameobjects some sort of label! So what game object naming system do you use then?

    And then there is the problem with long term maintainability of the code. If you don't use some sort of descriptive naming system that reflects the purpose of the game object, and in script names don't in some way match the name of the game object they are attached, to then surely it would make it hugely more difficult for a newby in the team to get their head around the app?

    Again....this sort of thing was emphasized to me in my Grad Dip Comp Science.
     
  32. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    It seems more like replacing one step with a different one to me......one that I can do a lot faster. But anyway......
     
  33. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,952
    One you have to do once versus one that need be done every time you decide the name is no longer ideal. Once again this doesn't matter as much with one man teams but with a studio this can and will happen more often.
     
    Mycroft likes this.
  34. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    But it gets it via reference and things will still stay referenced even when the GameObject name changes.

    Why would scripts have to be named based on the object they are placed on. A script should be a reusable component that you can use on many different gameobjects.
     
  35. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well for starters, this static binary tree would have to be there for the life of the app.

    And I assume that when the app ends there are no more references to the static binary tree which means it would all get garbage collected one way or another?

    And the static binary tree would only store references to game objects created in the editor, not game objects that I instantiate via code - I believe that gameobjects are always passed by reference into functions.

    Which I might add is some what unnerving as a C++ programmer where you explicitly choose whether objects are passed into functions by reference, pointer or value. And therefore whether or not the function is capable of altering the state of of the object that you pass into the function.
     
  36. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well I suppose that's what 'team work' and 'communication' are all about.

    I can also see how fixed interfaces could be rather useful as well.
     
  37. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    20,952
    Sounds like you haven't had a situation where it could happen yet. ;)
     
  38. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well, as an extreme example, I wouldn't think that it was sensible in calling my game object 'SaveButton' and calling the script attached to it 'FredSmith'. 'SaveButton' and 'SaveButtonManager' seem a lot more sensible and thoughtful for the programmer who comes after me and has to maintain my code.
     
  39. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    Never attended a comp sci class in my life. ;)

    As a general rule I don't like relying on names of GameObjects for much of anything. I tend to use names only as a human readable inspector handle. Naming conventions are pretty fragile and brittle. Some bigger teams use them, but it hardly makes sense for smaller projects.
     
  40. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160

    And everyone on your team is guaranteed to believe in the same naming structure and always follow the rules and never make a mistake. Expecting people to perfectly follow rules is a fools errand.

    But you obviously disagree. Great! Let me know how it works out.

    I'll continue to base my decisions on 17+ years of working in large teams with varied member experience/focus and working with realistic expectations vs expecting them to be perfect.
     
    Ryiah likes this.
  41. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well yes I have......at least in small teams with Visual C++ Windows applications.
     
  42. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    A significant part of coming to C# from C++ is trusting the run time to handle this stuff for you.

    A significant part of coming to Unity is trusting the engine to do the same.
     
  43. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well I tended to want to trust the lecturer's judgment - he/she had far more experience than me at the time.

    And having programmed for 15 years or what ever, I fully understand why they stressed it.
     
  44. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Well if you join a team I would have thought it would be polite to do your best to fit in with the established standards and conventions re coding! Not head off on a tangent and make everyone's work life a misery!

    Perhaps that is part of the problem here - not everyone in here (and perhaps in your team) has had formal training in programming!
     
    Last edited: May 26, 2016
  45. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Look it is a difference between C# and C++ that I just need to adapt to.

    But it is none the less unnerving for now to have to give up that layer of control - it requires a quite different mindset.
     
    Kiwasi likes this.
  46. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    So rereading the thread, where is the idea of Find and SendMessage reducing the number of scripts coming from? The two ideas seem to be totally unrelated to each other.

    Anyway, I've got to sleep now. But will pop back in the morning.
     
  47. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Not reducing the number of scripts, rather, reducing the amount of code you have to write in total.

    Below is a simple example of object oriented inheritance that reduces the amount of code you have to write and makes maintenance easier.

    Add to it class Square, class Triangle, class Trapezium.
    All of them have at least a width and a height, but the way you calculate their area is different.

    So point of inherritance in object oriented programming is that you DON'T have 'n' instances of the function seWidth(..), setHeight(...), int width and int height in 'n' classes corresponding to 'n' different shapes.

    It means that, if you need to change width and height to floats rather than integers then you make the change once in the base class, not 'n' times in 'n' different classes.

    So having established that paradigm, calling functions in Unity scripts by this method:

    MyScript s = GetComponent<MyScript>();
    s.FuncName();

    Totally breaks object oriented inheritance and polymorphism - it means you are forced into 'n' different classes/scripts with 'n' different instances of setWidth(..), setHeight(...), int width and int height.

    Hence the reason why I prefer to use SendMessage("FuncName", object) - it is generic.

    What I have done is use it like so "SendMessage("DoDispatchMessage", object) "
    void DoDispatchMessage(object)
    {
    DoReceiveMessage(object);
    }

    DoReceiveMessage(object) is a virtual function that you override in your derived classes as required and allows C# object oriented polymorphism to take effect.

    It also means that I need only look at one central function in all my script classes to find any bugs concerning inter-object communication. It is inspired by Microsoft's message map system in their Microsoft Foundation Classes - an excellent coding system for complex communications.

    I have many other criticisms of Microsoft, but I give them credit where it is warranted.


    Code (CSharp):
    1. #include <iostream>
    2. using namespace std;
    3.  
    4. // Base class
    5. class Shape
    6. {
    7.    public:
    8.       void setWidth(int w)
    9.       {
    10.          width = w;
    11.       }
    12.       void setHeight(int h)
    13.       {
    14.          height = h;
    15.       }
    16.    protected:
    17.       int width;
    18.       int height;
    19. };
    20.  
    21. // Derived class
    22. class Rectangle: public Shape
    23. {
    24.    public:
    25.       int getArea()
    26.       {
    27.          return (width * height);
    28.       }
    29. };
    30.  
    31. int main(void)
    32. {
    33.    Rectangle Rect;
    34.    Rect.setWidth(5);
    35.    Rect.setHeight(7);
    36.  
    37.    // Print the area of the object.
    38.    cout << "Total area: " << Rect.getArea() << endl;
    39.  
    40.    return 0;
    41. }
     
    Last edited: May 26, 2016
  48. Mycroft

    Mycroft

    Joined:
    Aug 29, 2012
    Posts:
    160

    Reality of game dev is teams that include many members with zero interest or experience with programming, much less training. Expecting them to follow your best-practices, which may often work counter to their best-practices, is ridiculous.

    Name based coding is slower to write, harder to debug, harder to maintain, is more brittle as teams get larger and runs slower. Being obstinate about how you want reality to change to fit your opinion of project development makes me think you haven't worked in a large team before.

    Also, stop acting like you're the only one with a formal education. Being insulting just makes you look like a twit.

    /done
     
    Ziplock9000 and Ryiah like this.
  49. boylesg

    boylesg

    Joined:
    Feb 18, 2016
    Posts:
    275
    Straw man argument! I never said I was the only one here with formal training.

    In fact I had been assuming that everyone in here did have some sort of formal programming training themselves.

    But that is clearly not the case!

    "Reality of game dev is teams that include many members with zero interest or experience with programming, much less training. Expecting them to follow your best-practices, which may often work counter to their best-practices, is ridiculous."

    And they are not my best practices - they the best practices devised by others far more experienced than me, were taught to me and that I see merit in.
     
  50. Baste

    Baste

    Joined:
    Jan 24, 2013
    Posts:
    6,294
    What I'm failing to see here is how basing your code around strings has anything to do whatsoever with OO programming.
     
    Kiwasi and Ryiah like this.