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?

8 Answers

8

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.

I don't have enough thumbs for this answer

Is this all still valid, +1.0 versions and 2 years later?

Glad to see you are still on this @Wolfram

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 MonoBehaviour B with OnEnable be run after another MonoBehaviour 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 (March 2016). Adding OnEnable in your low-order script DOES NOT SOLVE the problem unfortunately.

I can confirm that this DOESN'T WORK in 5.3.4f1. What worked for me was to change the execution order for the two scripts. Edit > Project Settings > Script Execution Order

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 Mono. When you "add" a component a lot things happens which you don't see and you can't influence.

btw: It behaves way different in a build than in the editor. When using instantiate in a build (tried web and win standalone) the order seems to be correct.

@Wolfram: Yeah take you point about Bunny83's intended point - sorry Bunny83. However since OnEnable is called before start it can already be too late to do instantiations or even finds! Wow what an utter mess monoBehaviours are. Having just played around with this in a new project I also see the whole instanceA.Awake, instanceA.OnEnable then instanceB.Awake, instanceB.OnEnable problem too.

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.

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. Much worse - for example - is an totally undefined and jagged destruction order)

Some of the info in previous is now old and outdated. Please refer to this flow chart for an accurate / up-to-date flow:

Source: Execution Order of Event Functions

Gah! Yeah, this order stuff is incredibly ugly. Just wanted to chime in with a couple of additional facts about Awake and OnLevelWasLoaded (as of 5.2):

Awake is not called if the gameObject that is on is inactive. This is unintuitive since Awake is called if the script itself is enabled.

OnLevelWasLoaded does not seem to be called for the first scene objects are in. Or at least in the Editor they are not called in the first scene. Less sure about the details here than for Awake - if anyone has a similar experience, let me know in the comments.

All of this wackiness makes me wonder if some other non-Start/Awake solution is needed…

Check this link, it provides execution order for all functions of unity

I hope it helps.