Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

OnEnable before Awake??

Discussion in 'Scripting' started by BornGodsGame, Oct 16, 2015.

Thread Status:
Not open for further replies.
  1. BornGodsGame

    BornGodsGame

    Joined:
    Jun 28, 2014
    Posts:
    587
    I always thought it was Awake, Start then OnEnable

    Two game objects, each with a script.

    on the first object, the script has an awake function that sets some public variables
    on the second object (enabled) there is a script that uses those variables in OnEnable

    it is a bit curious, because if I start the game with the second object already enabled, the variables I am getting in the second script are 0´s because the variables have not yet been set by the first scripts Awake.

    I solved the problem by invoking a method in the OnEnable function .1f seconds later. Just curious of an explanation of why that would be needed.
     
    dan_ginovker likes this.
  2. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
  3. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    What the chart doesn't explain is how executions of this is ordered between objects. One way you could interpret it is as if it will always call all Awakes before all OnEnables:
    Code (csharp):
    1.  
    2. Obj1.Awake();
    3. Obj2.Awake();
    4. Obj1.OnEnable();
    5. Obj2.OnEnable();
    6. Obj1.Start();
    7. Obj2.Start();
    8.  
    As you've noticed, this is not the case.

    This is an example of what it actually does (actually vaguely explained on the page @martinmr linked)
    Code (csharp):
    1.  
    2. Obj1.Awake();
    3. Obj1.OnEnable();
    4. Obj2.Awake();
    5. Obj2.OnEnable();
    6. Obj1.Start();
    7. Obj2.Start();
    8.  
    So OnEnable is called just after Awake per object.
    One object's Awake is not guaranteed to run before another object's OnEnable.
     
    DatDzua, Crokett, fnnbrr and 47 others like this.
  4. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,513
    Yeah, I'm not a fan of this ordering myself either.

    I like to have code in OnEnable and OnDisable that turn on or off some stuff in my script based on that. But my OnEnable expects other scripts to be prepared and ready (Awake was called).

    At first I was checking if the script had been started and calling the enable code from both Start and OnEnable. But then I encapsulated it into a special base class that all my scripts inherit from that has a new method called 'OnStartOrEnable' that calls in the order in the way I would rather (and you seem to expect).

    You can see it in here:
    https://github.com/lordofduct/spacepuppy-unity-framework/blob/master/SpacepuppyBase/SPComponent.cs
     
    dan_ginovker and ThermalFusion like this.
  5. martinmr

    martinmr

    Joined:
    Mar 25, 2015
    Posts:
    325
    ah ok if you want to know it between different scripts you have to also have to think about a Script Execution Order
    http://docs.unity3d.com/Manual/class-ScriptExecution.html

    so like documentation says, let's look what wood happen if we have 3 Scipts.

    Script_1 with Awake() OnEnable() and Start (), the same with Script_2, Script_3 .

    If all of our Script are on default time because we haven't done any adjustments in the ScriptExecution scripts will be called like:

    Code (CSharp):
    1. Script_1.Awake()
    2. Script_1.OnEnable()
    3. Script_2.Awake()
    4. Script_2.OnEnable()
    5. Script_3.Awake()
    6. Script_3.OnEnable()
    7.  
    8. Script_1.Start()
    9. Script_2.Start()
    10. Script_3.Start()
    but what at this point is important. if they are all at default time, it is not 100% sure that the scripts methods will be called this way every time. what also could happen is das Script_3.Awake() is called before the other Script_1.Awake() and Script_2.Awake(). So if you build to your phone the internal order of script execution at default time can change and you may get some errors.

    But what NOT will happen is, that Script_3 Script_2 or Script_1.Start() will be called before an OnEnable or Awake of any other script!

    So if we now set the Script Excecution of Script_1 as 100, Script_2 stays Default Time, Script_3 to -100.
    (Every Script not shown in the list ate the ScriptExecution are standard at Default Time).

    In this case our order how Start Awake and OnEnable will be called now this way

    Code (CSharp):
    1. Script_3.Awake()
    2. Script_3.OnEnable()
    3. Script_2.Awake()
    4. Script_2.OnEnable()
    5. Script_1.Awake()
    6. Script_1.OnEnable()
    7.  
    8. Script_3.Start()
    9. Script_2.Start()
    10. Script_1.Start()

    Hope this makes all clear, if still a question, just ask here :D
     
    Last edited: Oct 16, 2015
    sawnch, zeimhall, codxr and 3 others like this.
  6. Nigey

    Nigey

    Joined:
    Sep 29, 2013
    Posts:
    1,129
    Yeah OnEnable always gets called multiple times for some reason. It's why I always have a base class with a bInitialised check, to see whether Awake() or Start() has been called (whichever I wanna check).

    Code (CSharp):
    1.     public abstract class BaseFramework : MonoBehaviour
    2.     {
    3.         protected bool bInitialised = false;
    4.  
    5.         // MonoBehaviours
    6.         protected virtual void Awake() { Initialise(); }
    7.         protected virtual void OnEnable() { if (!bInitialised) return; }
    8.  
    9.         // protected methods
    10.         protected virtual bool Initialise()
    11.         {
    12.             // Other initialisation stuff
    13.             return (bInitialised = true);
    14.         }
    15.     }
     
  7. BornGodsGame

    BornGodsGame

    Joined:
    Jun 28, 2014
    Posts:
    587
    Ok, thanks for the explanation. I think my solution will work fine for my situation ( having a delayed invoke inside the OnEnable), but I should probably delay the invoke a little more for the live environment where I will have a lot more scripts with awake. The vast majority of the time, the OnEnable will be getting run after the game has been running so won´t have this issue, but that initial OnEnable on startup could have a bunch of my trees starting the game as chopped stumps :)
     
  8. ThermalFusion

    ThermalFusion

    Joined:
    May 1, 2011
    Posts:
    906
    In your case I would probably set a bool to true in start and then check it in OnEnable, and do nothing if start has not run yet.
     
    kyleshell likes this.
  9. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860
    OnEnable can be a coroutine. It's possible to yield a frame or two before taking any action.
     
    ModLunar likes this.
  10. BornGodsGame

    BornGodsGame

    Joined:
    Jun 28, 2014
    Posts:
    587
    but that would mean the first OnEnable might not get run for a very long time if the Object is not disabled and enabled again.
     
  11. BornGodsGame

    BornGodsGame

    Joined:
    Jun 28, 2014
    Posts:
    587
    yeah, basically what I did, but since I didn´t need to pass anything, I just used Invoke with a small delay.
     
Thread Status:
Not open for further replies.