- Home /
OnEnable, Awake, Start order
I use a "framework" class that is set to run before all the other scripts (-300). This class has an Awake method. I also use another normal monobehaviour which defines the OnEnable method.
Once the application runs, the OnEnable of the second monobehaviour is called before the awake of the framework class. Is this the intended behaviour?
Answer by Wolfram · Jun 27, 2012 at 03:38 PM
It's rather complicated.
[
Update 5.1.1: I didn't re-test everything, but here is what seems to be fixed/different in both 5.x and 4.x (tested 5.1 and 4.6), as opposed to 3.5:
The bug that the user-defined execution order is ignored if one (but not all) script has an "OnEnable()" function (=see "EDIT3" below) seems to be fixed.
OnLevelWasLoaded() is no longer called before Awake(), and always after OnEnable()
The execution order of OnLevelWasLoaded() is still arbitrary and cannot be user-defined
OnEnable() is no longer called in successive levels if DontDestroyOnLoad is active.
]
A simple test with 3.5.2 revealed, most concurrent functions (well, at least the ones I tested: Awake, Start, OnEnable, FixedUpdate/Update/LateUpdate) abide by the execution order defined for the scripts. The execution order of OnLevelWasLoaded is not affected by that, and therefore cannot be influenced by the user. This could be considered a bug.
The order of the four methods of a script related to initialization is always:
Awake()
OnEnable()
OnLevelWasLoaded() // (only on scene changes)
Start()
However, if your script was disabled in the first place(via Script.enabled=false), this order changes to:
OnLevelWasLoaded() // is now called first, before Awake()! (only on scene changes)
Awake()
[OnEnable()/Start() are not executed until the script is actually enabled]
In addition, note that Awake() and OnEnable() calls are connected/interleaved. Meaning, assuming a particular, user-defined execution order A and B with A*<*B,
each individual script of type A will execute its Awake(), immediately! followed by its OnEnabled()
then all scripts of type B will do the same
then all OnLevelWasLoaded() will be executed, in a (presumably) fixed but unpredictable order (assuming this scene was freshly loaded - otherwise this step is skipped completely)
then all Start() will be executed, in the order A,B
In particular, this means that OnEnable() of type A will be executed before Awake() of type B, while OnEnable() of type B will be executed after Awake() of type A. This overview explains it more clearly:
Awake() of Type A, instance 1
OnEnable() of Type A, instance 1
Awake() of Type A, instance 2 // order of instances cannot be influenced
OnEnable() of Type A, instance 2 // order of instances cannot be influenced
Awake() of Type B
OnEnable() of Type B
OnLevelWasLoaded() of Type ? // order cannot be influenced
OnLevelWasLoaded() of Type ? // order cannot be influenced
Start() of Type A
Start() of Type B
EDIT: Hm, this is a total mess. If DontDestroyOnLoad() is activated for such a script, this will get even more complicated, and the order changes yet again to:
[Awake() is never called again, only the very first time]
OnEnable()
OnLevelWasLoaded() // as opposed to being called before OnEnable(), when DontDestroyOnLoad() is not activated
[Start() is never called again, only the very first time]
EDIT2: In addition, when DontDestroyOnLoad() is active, the user-defined execution order is no longer abided by!, neither by OnEnable(), nor by OnLevelWasLoaded().
EDIT3: WAH! I'm gonna stop testing now, this is a neverending story... As @Noisecrime noticed, there is actually another bug, where user-defined execution order is overriden if the script has an OnEnable() function!
Script A has OnEnable, Script B has not:
Awake() of Type A
OnEnable() of Type A
Awake() of Type B
Script B has OnEnable, Script A has not:
Awake() of Type B
OnEnable() of Type B
Awake() of Type A // after Type B!
And note that Awake is called even on a disabled component, but not if the game object it is attached to is inactive. (This may or may not seem obvious, it wasn't to me ... ;-)
For added fun, in the editor environment, OnDrawGizmos may be called before Awake ... so make sure your gizmo code checks for uninitialized data.
Is this all still valid, +1.0 versions and 2 years later?
Answer by Noise crime · Jun 27, 2012 at 02:08 PM
From the sound of it, this is the 'OnEnable' bug with script execution order. That is I suspect your 'framework' script does not have an OnEnable method in it, in which case for some odd reason it will get trumped in execution order by the scripts that do, despite any ordering you add to the script execution.
To fix this issue, simply add an OnEnable method to your framework script.
I believe this actually answers @sebas' question. See my answer for a more detailed explanation/analysis.
It may be fixed in Unity 5.1.3, or maybe my case has some subtle differences.
I tried to make a $$anonymous$$onoBehaviour B with OnEnable be run after another $$anonymous$$onoBehaviour A with no OnEnable, and it worked. I wanted A.Awake() to quickly deactivate the game object of B so that B.OnEnable() was not called at the beginning of the game (not critical, but it would cause unneeded initialization of B just before being deactivated anyway). Script A managed to deactivate game object B before B.OnEnable() was called.
This IS NOT FIXED even in the latest Unity ($$anonymous$$arch 2016).
Adding OnEnable in your low-order script DOES NOT SOLVE the problem unfortunately.
I can confirm that this DOESN'T WOR$$anonymous$$ in 5.3.4f1. What worked for me was to change the execution order for the two scripts.
Edit > Project Settings > Script Execution Order
Answer by Bunny83 · Feb 17, 2012 at 04:19 PM
OnEnable and Awake are called when the objects / script instance is created. They are propably called from the internal constructor. They are even called before Instantiate returns. There is no way to influence when awake / OnEnabled is called on scene objects. The execution order you can set in Unity only influences the Unity generated events like Start, Update, LateUpdate ...
Avoid code in Awake which relies on other object. Start is made for this purpose. Start is called after all scene objects are created and all Awake function has been called. In general you should use Start to initialize object dependencies.
Thanks for the answer. Are you telling me that the script execution order controls only the Start order and not the Awake order?! However I do not think they are called inside the constructor, but I do think they are called right after.
Yes, you can't control when Awake is called since it's actually the direct replacement for the constructor. Awake might be called from the constructor, but we don't know how Unity handle those things behind the scenes. That's why i said the "internal constructor". Don't forget that almost every object in Unity has also a c++ native code class-part behind the scenes. Unity isn't written in managed code, only the scripting environment uses $$anonymous$$ono. When you "add" a component a lot things happens which you don't see and you can't influence.
According to the docs there are several aspects that are incorrect from Bunny83's reply. Firstly script execution order does deter$$anonymous$$e when Awake is called (http://docs.unity3d.com/Documentation/Components/class-ScriptExecution.html). Secondly 'Awake is called after all objects are initialized so you can safely speak to other objects or query them' (http://docs.unity3d.com/Documentation/ScriptReference/$$anonymous$$onoBehaviour.Awake.html), so its perfectly safe to use code in Awake that replies on other objects.
Further more you need to take care if using Start to initialise object dependencies since if the object is enabled, its OnEnable will be called first, and if you try to use those dependencies they will not be set up yet.
As to your problem check my reply below and see if its to do with a known bug when using OnEnable in other scripts but not in the one you are trying to force the script execution order for.
@Noisecrime: I believe with "Avoid code in Awake which relies on other object" @Bunny83 is talking about situations where you are referring to other objects that also initialize themselves in Awake(). For example, for a given scene hierarchy where the same script type is attached to all objects, the children (or some children) of an object might already have their Awake() being executed, while the parent object has not. Or vice versa - it might be non-deter$$anonymous$$istic. In addition, if you are instantiating stuff in Awake(), you cannot relie upon in other Awake() functions that these objects have been created already. So you might want to do your instantiations in Awake(), but any Find()/FindObjectByType() etc. in Start.
The whole execution order thing doesn't work at all. It does work when a level is loaded, but try instantiating a prefab at runtime... The only thing that follows the execution order is Update / LateUpdate ... Start / Awake / OnEnable ... are not in the specified correct order.
You also have to distinguish between serialized objects which are stored in a scene and runtime generated instances. Awake is called when the object is "loaded". Again, when you call AddComponent to add a certain script, awake will be called before the AddComponent function returns. Same thing for Instantiate(). Awake and OnEnabled will be called before Instantiate returns. If you have two scripts attached that have been arranged in a certain execution order, they won't follow it.
btw. I've done a lot analysis on this issue in the past. The script execution order is a quite new feature which was buggy since it has been implemented. Afaik they fixed it partially, but in the end it still doesn't work.
It actually doesn't make much sense to overanalyse it. Fact is: you can't rely on it, so don't rely on it!
It is true that when a scene is loaded, all serialized objects are created before Awake is called. The objects are actually created two times (just put a debug log into the constructor). First time in the object creation order (the order they have been created / saved / ...) and again when they get deserialized. The deserialization for scene objects follows the execution order. Then all Awake functions are called then Start. They follow the execution order, but only when they are serialized objects in a scene.
You shouldn't take the docs for granted. There are many cases where the docs had wrong examples or misinformation. It often describes how it should work, not how it actually works.
Answer by Ashkan_gc · Feb 17, 2012 at 02:31 PM
The manual is not that clear about it. It mentioned OnEnable after Awake in list order but it only said clearly that all Awakes will be called before any Start. again in summary it only shows Start and Awake and not OnEnabled. but for Awake says it will be called After Instantiation and for OnEnabled it says after object becomes enable so theoratically Awake should be sooner than OnEnable.
Answer by Immanuel-Scholz · Nov 07, 2013 at 01:33 PM
I just submitted another strange bug, where the scripting order gets violated. If you have the following setup in your hierarchy (where "Prefab" is any prefab instance):
GameObject
+- Prefab
+- GameObject
+- Prefab
+- ObjectWithUnmportantComponent
ObjectWithImportantComponent
Then the component of "ObjectWithUnmportantComponent" gets executed first, even if it has a script order number higher than a component in "ObjectWithImportantComponent".
Did you ever get resolution on this bug? We're seeing something similar that is completely messing up our scripts (unreliable order of execution will do that to you!)
Unfortunately not.
We are doing our own execution callback system (for various other reasons as well. This one in case here is actually not the biggest problem. $$anonymous$$uch worse - for example - is an totally undefined and jagged destruction order)
Your answer
Follow this Question
Related Questions
Execution Order of Scripts - Awake and OnEnable 1 Answer
Should OnEnabled() be changed to be called after Start()? 1 Answer
If a script is attached to more than one gameObject, will Start() & Awake() run more than once? 2 Answers
Does the access modifier of Start(), Awake(), OnEnable() make a difference to Unity? 3 Answers