No. We should get it in Awake !
Here’s the rundown:
Awake
- new() C# classes
- GetComponent(s)
- GetComponent(s)InChildren
- Assign references to static fields/classes (singletons)
- avoid calling methods on these objects
Start or OnEnable
- GetComponent(s)InParent
- get references that are assigned in Awake to static classes or singleton instances
- call methods of any reference you obtained
In short: Awake is for getting or new’ing references that the script can be certain of at this point, eg they are on the same object or children. In Awake you should not call methods of other references, perhaps with the exception of cases where you are absolutely certain that the object will not call out to, require or try to obtain external references - such as a static registry class that holds references and provides them to other scripts.
Start or OnEnable is for obtaining “external” (not in the active gameobject or its children) references and calling methods of any reference you obtained.
Profile it!
You can also Ctrl+click (“Goto Implementation”) the property or method in the IDE to inspect its (possibly decompiled) code. Usually in Unity you will find many of these are marshalled to native C++ code, that’s as far as we can (easily) see.
Generally, it’s best pratice to keep your code short and simple. DRY principle.
I often see code like this:
this.gameObject.transform.position = new Vector3(..);
Merely for legibility we should write it as follows:
transform.position = new Vector3(..);
It’s even worse with GetComponent. This is what we should write:
var targetScript = hit.Collider.GetComponent<TheTargetScriptThatINeed>();
if (targetScript.thisflag && targetScript.thatFlag == false && targetScript.counter > 10)
// do something
Now imagine this … most newcomers don’t even bother to create the targetScript variable. Whether this is slower or not is practically irrelevant - it utterly makes the code above illegible and unmaintainable - that’s what matters!
Hence why best practice recommends using one canvas per each group of UI elements that change together. Eg don’t use a single canvas for the entire HUD, instead have one for the health bar, one for the team status, one for the minimap, and so on.
I recall from the past that it’s not “free” meaning if you first check isActiveSelf or isActiveInHierarchy you can avoid some extra processing. However, this really only matters in tight loops running every frame! The extra processing is most likely almost entirely due to marshalling the method call from C# to C++ - the transition between language barriers is not free.
There’s another situation however, which is more important to know about: if you instantiate several child objects, sometimes you don’t want them to start active. You may not even want them to run their Start/OnEnable methods upon first instantiation. The solution is to do this:
var wasActive = gameObject.isActiveSelf;
gameObject.SetActive(false);
// instantiate many children here which are supposed to start inactive
var child = Instantiate(..);
child.SetActive(false);
gameObject.SetActive(wasActive);
Because the parent is inactive at the time of instantiating, the new instances are not starting their scripts which allows you to set these new objects inactive while instantiating. This can save needless initial processing (speak: loading) time if you only need one or few of these active (eg weapons) and switch between them.