Question about Unity documentation GameObject.Find

So I came to Unity when I first started programming so I attempted to pretty much follow the Unity Documentation as much as possible when I was starting and continued those habits even after learning how to work Unity fairly well.

So this whole time all I remember about GameObject.Find() was the Unity Documentation description:

“For performance reasons it is recommended to not use this function every frame Instead cache the result in a member variable at startup or use GameObject.FindWithTag.”

I feel that following this advice has made things exceedingly difficult for having unique game activity in specific levels.

For example the first time you encounter an enemy it might display text just that one time. Or perhaps in one level the certain enemy might drop a key or trigger bossMusic where later in the game they might just be a normal enemy.

My point is that this whole time I’ve been loading up a bunch of excess variables for all my scripts for what many times might be rare occurrences in the game, some might only be used in one specific level and they were always isolated game logic (never every Update()). I was doing this because the documentation made it seem like using GameObject.Find was terrible and should only be used at StartUp() or with tags (never used tags yet).

So my question is does GameObject.Find() really have such bad performance when used intelligently? The documentation makes it sound like for some unknown reason people would only use it in Update() every frame but what about when you use it for specific events that are only called once per action, or very rarely like my examples above with the excessive variables.

In this example the following code block only occurs in one unique enemy Update() function and can at most occur once every time you are playing in that scene.

Wouldn’t it be better to just use GameObject.Find() if it’s called once instead of having all these excessive variables like I was doing in the past? Probably a stupid question just kind of annoyed how much trouble I’ve been going through setting up my game because of this and thinking GameObject.Find() was the worst thing ever. I probably have dozens of variables I could eliminate from my scripts by not following their advice.

So why do they say tags are OK? And why is GameObject.Find() OK at Start() but not OK if used just for one event? Is there really a difference in the GameObject.Find() function when used after Start()? Or do they just assume people would use it in every Update() frame for some unknown reason?

Example of how I might use GameObject.Find() for a very rare event that could only be called once or in unique circumstances (not every Update()) instead of declaring extra variables:

void Update()
{

//other Update stuff that can potentially lead to this unique event

if ((GlobalDataScript.currentLevelInt == 8) && (thiefRunAwayBool == true))
					{
						//*** open bridge...	
						GameObject animationObject = GameObject.Find("Draw Bridge");
						animationObject.animation.Play ();
						
						//could also just disable collider for other levels...
						GameObject colliderObject = GameObject.Find ("Bridge Entrance Collider");
						Destroy(colliderObject);

thiefRunAwayBool = false;
					}
}

It seems this kind of thing is much easier to deal with than having a ton of generally useless variables attached to all your scripts to hold those 2 game Objects for one particular level.

Just wanting to know if there really is some kind of horrible thing that happens when using GameObject.Find() after start like their documentation would lead a new programmer to believe.

So GameObject.Find could be very expensive and cause glitching (it depends on the hardware, the complexity of the scene and the amount of processor already in use). Instead why don’t you do something like this:

   using UnityEngine;
   using System.Collections;
   using System.Collections.Generic;

   public class QuickFinder : MonoBehaviour
   {
         static Dictionary<string, GameObject> cache = new Dictionary<string, GameObject>();
         public string quickFindName;
         void OnEnable() 
         {
             quickFindName = string.IsNullOrEmpty(quickFindName) ? name : quickFindName;
             cache[quickFindName] = gameObject;
         }
         void OnDisable()
         {
             cache.Remove(quickFindName);
         }
         public static GameObject Find(string name)
         {
             return cache.ContainsKey(name) ? cache[name] : null;
         }
   }

Drop one of those on the things you need to find, set their unique QuickFind name and then get them using:

        var foundGo = QuickFinder.Find("SomethingToFind");

I use GameObject.Find() a fair amount as I want to reference named objects rather than tags, which are often shared between many objects. I do, however, restrict this to the Start() function. Individual uses are just fine but you may notice the impact if your Update() is rather heavy anyway. I guess its similar to using tons of nested if/else statements or iterating a large array, in that, it could take some time to get through all the cases, especially if you have many objects.

As I’m used to using it this way, I can’t imagine a situation where I’d need to call it every frame. Once you have found the object, using GetComponent every frame is a lot less intensive.

I think the point about Start() is that, normally, the startup time of an object isn’t critical, except that it must be completed before Update() runs. Doing this as a one-time in Update() can cause a visible glitch/hang etc, during the ‘normal’ operation of the object, potentially increasing the length of that one frame.

Do you assemble your rifle before combat or do you try to stick it together while you are running across the field? :smiley:

Honestly though, I’d say one time use is just fine, unless you have a large, intensive game.