Search Unity

  1. Unity 2019.2 is now released.
    Dismiss Notice

Awake and Start - Frame execution

Discussion in 'Editor & General Support' started by 3gogames, Dec 7, 2018.

  1. 3gogames

    3gogames

    Joined:
    Jul 28, 2015
    Posts:
    31
    HI all,

    I'm encountering some problems trying to understand which logic is used to decide the MonoBehaviour's Start execution frame.

    According to documentation (https://docs.unity3d.com/2018.3/Documentation/ScriptReference/MonoBehaviour.Start.html) I have:

    Start may not be called on the same frame as Awake if the script is not enabled at initialisation time.

    but using this simple script:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class MonoBehaviourCallbackLogger : MonoBehaviour
    4. {
    5.     // MonoBehaviour's interface
    6.  
    7.     private void Awake()
    8.     {
    9.          Log("Awake");
    10.     }
    11.  
    12.     private void OnEnable()
    13.     {
    14.          Log("OnEnable");
    15.     }
    16.  
    17.     private void Start()
    18.     {
    19.           Log("Start");
    20.     }
    21.  
    22.     // INTERNALS
    23.  
    24.     private void Log(string i_MethodName)
    25.     {
    26.         Debug.Log("[" + gameObject.name + "] " + i_MethodName + " (Frame: " + Time.frameCount + ")");
    27.     }
    28. }
    with an already active game object in scene I saw:

    [GameObject] Awake (0)
    [GameObject] OnEnable (0)
    [GameObject] Start (1)

    So, I assume that Start is called the frame after Awake (and it make sense to me).
    As a proof of this (and a proof that the documentation should be updated and corrected) I have tried to instatiate another copy of the simple object used above in the Awake of the first object. And the result was:

    [GameObject] Awake (0)
    [GameObject(Clone)] Awake (0)
    [GameObject(Clone)] OnEnable (0)
    [GameObject] OnEnable (0)
    [GameObject] Start (1)
    [GameObject(Clone)] Start (0)

    And this also make senso to me (cause Awake and OnEnable should be called in place when using Instantiate method).
    However this is different from documentation cause I found:

    Where objects are instantiated during gameplay, their Awake function is called after the Start functions of Scene objects have already completed.

    So I was expecting a result like:

    [GameObject] Awake (0)
    [GameObject] OnEnable (0)
    [GameObject] Start (1)
    [GameObject(Clone)] Awake (0)
    [GameObject(Clone)] OnEnable (0)
    [GameObject(Clone)] Start (0)

    However this does not make any sense (in my personal opinion).

    Anyway, the point is: assuming that Start is after Awake (as the logger has shown), When I load a new scene, object in the new scene does the Start function in the same frame of the Awake.

    How is this possible?

    Can anyone give a detailed explaination of how Start and Awake are called or delayed?
    I hope it's deterministic...

    I'm implementing a UI System for our games and this is very important to me.

    Thank you all!

    Best regards,
    Andrea
     
    neonblitzer likes this.
  2. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,624
    https://docs.unity3d.com/2018.2/Documentation/Manual/ExecutionOrder.html

    I don't know why would you expect awake1/onenable1/start1/awake2/onenable2/start2/ order? Nothing indicates in the documentation that it should happen.
    The only guarantees you get are that
    - one object's Start will come before its Update (upon scene load it will be called before the first frame, if you add an object, it will be called before the first Update)
    - one object's OnEnable will be called before the Start method
    - one object's Awake will be called before the same object's OnEnable
    - on scene start all Awake and OnEnable will be called before the very first Start (regardless of object), but it's not true for later

    Since there is no other guarantees, Unity suggests to use the Awake function to look for external references and start the data-exchange on Start.

    If you're adding to new objects in the same frame you don't have any guarantees that one's Awake function will be called before the other or one's Start function will be called the other's Awake. During game play you will need to store references to the newly created objects and set up the references manually.

    ps: maybe I misunderstood something?
     
  3. 3gogames

    3gogames

    Joined:
    Jul 28, 2015
    Posts:
    31
    Thanks @LurkingNinjaDev

    I didn't expect awake1/onenable1/start1/awake2/onenable2/start2. I just said that, according to the docs (that say: Where objects are instantiated during gameplay, their Awake function is called after the Start functions of Scene objects have already completed), I understand that order (if object 1 is already in scene and instantiate object 2).

    Anyway, my question is why if I play a simple scene I obtain:

    [GameObject] Awake (0)
    [GameObject] OnEnable (0)
    [GameObject] Start (1)

    while if I load a new scene with the same object I get this:

    [GameObject] Awake (0)
    [GameObject] OnEnable (0)
    [GameObject] Start (0)

    Why Unity does not "delay" start in the second case exactly like the first case? Or why Unity delay the start in the first case and not in the second?

    Thank you for your help.
     
    neonblitzer likes this.
  4. Lurking-Ninja

    Lurking-Ninja

    Joined:
    Jan 20, 2015
    Posts:
    4,624
    No problem. :) So, it's not really delay. When the scene is loaded and starts the initialization happens outside of frames. It's not zero frame, it's not frame it's the load and initialization. The Start will be called in the first valid frame when the object becomes enabled. Which means the first frame on scene load and the same frame on object creation/instantiation.
    Delaying this would mean you can't set up your object in the same frame when you have created it (sort of). And my guess is that the Start call is in the update loop with an "if not started yet" clause right before the Update.
     
  5. 3gogames

    3gogames

    Joined:
    Jul 28, 2015
    Posts:
    31
    I agree with you about Start called in the update loop with an "if not started yet".
    The only thing that sounds strange to me is the fact that when you start the application Unity is not be able to call Start the very first frame (so it need a frame for initialization). And this occurs when also you instantiate a prefab from script.
    But if you load a scene, Unity become able to create, initialize and start Update loop (Start/Update) of new objects in just one frame.

    Anyway thanks, I'll think another solution that does not rely on Start execution frame.

    Thanks again. Have a nice day.