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!