Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Confused by Awake() documentation on enabled / disabled script

Discussion in 'Scripting' started by redhuck, Sep 20, 2023.

  1. redhuck

    redhuck

    Joined:
    Jan 14, 2022
    Posts:
    6
    Hello,

    On the Unity documentation of MonoBehaviour.Awake(), I read the explanation starts with the following mention : "Awake is called when an enabled script instance is being loaded."

    But my understanding is that Awake() is called even if the script is disabled.
    So isn't the mention kind of wrong?
    Shouldn't it be something like "Awake is called when a script instance is being loaded."?

    Thanks in advance...
     
  2. bugfinders

    bugfinders

    Joined:
    Jul 5, 2018
    Posts:
    711
    Well to answer your question about when its called, did you try it?
     
    Kurt-Dekker likes this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    EDIT: See posts below for more nuance.

    Code (csharp):
    1. using UnityEngine;
    2.  
    3. // @kurtdekker
    4. // - make a completely-blank scene
    5. // - make two GameObjects, name them ACTIVE and INACTIVE
    6. // - add this script to each GameObject
    7. // - set one GameObject to Active and the other to Inactive
    8. // - run
    9.  
    10. public class ReportNameOnAwake : MonoBehaviour
    11. {
    12.     void Awake()
    13.     {
    14.         Debug.Log(GetType() + ".Awake(): my name is " + name);
    15.     }
    16. }
     
    Last edited: Sep 20, 2023
    bugfinders likes this.
  4. redhuck

    redhuck

    Joined:
    Jan 14, 2022
    Posts:
    6
    Are you asking if I tried if a Awake() is called even when the script component is disabled?
    Yes I tried, or at least I think I tried...

    I write the following script and make it a component of an active gameObject.
    But I uncheck the script component to make it disabled, just like the attached picture.
    And when I play, I see "awake" is logged in console.
    So I think the Awake() is being called even when it's disabled.

    using UnityEngine;
    public class NewBehaviourScript : MonoBehaviour
    {
    void Awake()
    {
    Debug.Log("awake");
    }
    }

    awakeTest.png
     
  5. julienkay

    julienkay

    Joined:
    Nov 12, 2013
    Posts:
    159
    This is by design. If you read a bit further in the documentation you will find "Awake is called even if the script is a disabled component of an active GameObject."
     
  6. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,563
    Thanks for that callout... I think I see the confusion.

    What you are seeing is the cascade of Unity initialization in a running scene.

    YES you unchecked enabled.

    But when the scene is loaded and .AddComponent<T>() is called on your behalf, new script instances are enabled and there is no way to change this... UNLESS the GameObject is disabled.

    Now... long after AddComponent<T>() has happened and Awake() has been called... Unity deserializes the state of that script, all the public serializables, such as .enabled

    Now it looks disabled... and yet Awake fired.

    I retract my troll observation above. :)



    More broadly...

    Serialized / public fields in Unity are initialized as a cascade of possible values, each subsequent value (if present) overwriting the previous value:

    - what the class constructor makes (either default(T) or else field initializers, eg "what's in your code")

    - what may be saved with the prefab

    - what may be saved with the prefab override(s)/variant(s)

    - what may be saved in the scene and not applied to the prefab

    - what may be changed in the scene and not yet saved to disk

    - what may be changed in OnEnable(), Awake(), Start(), or even later

    Make sure you only initialize things at ONE of the above levels, or if necessary, at levels that you specifically understand in your use case. Otherwise errors will seem very mysterious.

    Here's the official discussion: https://blog.unity.com/technology/serialization-in-unity

    If you must initialize fields, then do so in the void
    Reset()
    method, which ONLY runs in the UnityEditor.

    Field initializers versus using Reset() function and Unity serialization:

    https://forum.unity.com/threads/sensitivity-in-my-mouselook-script.1061612/#post-6858908

    https://forum.unity.com/threads/crouch-speed-is-faster-than-movement-speed.1132054/#post-7274596

    To avoid complexity in your prefabs / scenes, I recommend NEVER using the
    FormerlySerializedAsAttribute
     
  7. redhuck

    redhuck

    Joined:
    Jan 14, 2022
    Posts:
    6
    Now I get it.
    It's very clear now.
    Thank you so much!
     
    Kurt-Dekker likes this.