- Home /
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:
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html
"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.
Answer by whydoidoit · Sep 26, 2013 at 09:09 AM
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");
$$anonymous$$ thanks for the answer! It does appear that just using GameObject.Find is causing some unexpected behavior on my phone while appearing to work on PC.
So on the bright side my efforts for extra variables this whole time wasn't a waste. $$anonymous$$ind of disappointed that Unity can't use GameObject.Find() without causing all those problems like you were saying with certain devices, processor use, etc.
It seems like Unity would be super nice and convenient to use if that stuff worked consistently.
I haven't tried dictionaries at all yet but that looks like it could have some potential for sure. Will need to experiment with it a bit to see how easily I could apply it to something like my example above.
I guess they didn't want to waste the memory of caching every game object and dealing with the circumstances where there are many with the same name etc. Still...
So with Unity 4.3 I noticed this patch note:
"GameObject.Find doesn't allocate internal memory"
So it seems you were spot on with the caching memory thing. I'm wondering though would this have any effect on being able to now use GameObject.Find outside of Start or Awake()?
Also I've started using Tags a ton since when I posted this so those seem to work fine for me but it still seems like it could be easier in certain circumstances not having to use a tag and being able to use GameObject.Find outside of Start() or Awake().
Well its horses for courses. I haven't used a GameObject.Find in the last three or four projects I've worked on.
What I do is:
Allocate variables in the inspector
Use a ComponentFinder script based on a Dictionary (per above) as this is an O(1) operation rather than O(f(n)) - (it's performance is irrespective of the number of objects in the scene).
Answer by meat5000 · Nov 21, 2013 at 12:47 AM
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? :D
Honestly though, I'd say one time use is just fine, unless you have a large, intensive game.
Ya I agree it makes sense not assembling a rifle in combat haha.
I wouldn't use GameObject.Find for every frame but last time I tried to use it as a one time thing during run time it worked for PC but not for Android.
So I was wondering if this change in 4.3 could potentially fix this kind of thing since I thought it was quite strange it didn't work in Android.
I've not encountered this. $$anonymous$$y project is Android only at the moment! Strange stuff :)
Hmm now that I think about it some more, it may have been some other problem causing the GameObject.Find() to not work for Android but work for PC.
I can see right in my example it was about playing a bridge animation. Wow my brain just gets so scrambled dealing with all the game program$$anonymous$$g stuff, just too much for my brain to keep track of especially with my drinking problem haha.
So I now remember that for some reason the PC build would play the bridge animation and the Android build would not. I believe it had something to do with the Animation "Culling Type" setting. For some reason the PC build seems to do a much better job playing the animations even when the objects aren't set to "Always Animate".
I'm guessing PC has a bigger range or somehow can see through walls or something... doesn't really make sense to me but I had the bridge set to automatically play the animation and then immediately pause after like 1 frame so it would be in the upwards position for a drawbridge (if you don't play the animation it's down). And doing this at the start of the scene allowed the PC animation to start and immediately stop as expected. However the Android build would not even start the animation.
Since then I have set them both to "Always Animate" so they both work.
So maybe this whole time my problem had nothing to do with GameObject.Find() but rather Animation "Culling Type" settings.
Such a steep learning curve for a noobie like me. For some reason I just take things for granted ins$$anonymous$$d of always assu$$anonymous$$g certain settings won't work. Took me FOREVER to even discover that "Culling Type" was important :(
All these inconsistencies with the animation behavior for PC and Android have nothing to do with my project settings. It seems Unity does this kind of stuff by default and can confuse the heck out of amateurs like myself.
Your answer
Follow this Question
Related Questions
How do I use iTween outside of start? 0 Answers
bool value does not change 1 Answer
Start, Awake, Update. Any other ways to call functions from an empty GameObject? 3 Answers
How do I replace Invoke Repeating to allow a repeat rate change 1 Answer
Is it absolutely unconditionally true that Start runs BEFORE the FIRST Update? 3 Answers