Search Unity

Start() called but not Awake(), why?

Discussion in 'Scripting' started by wx3labs, Nov 28, 2020.

  1. wx3labs

    wx3labs

    Joined:
    Apr 5, 2014
    Posts:
    77
    I've run into a problem that's got me stumped. I have a standard TextMeshPro Dropdown that's throwing an exception when expanded because its m_AlphaTweenRunner property isn't initialized. I added some debug statements to Awake and Start to try to figure out why:

    Code (CSharp):
    1. protected override void Awake()
    2.         {
    3.             Debug.Log("Okay! I'm awake: " + this.GetType().Name);
    4. #if UNITY_EDITOR
    5.             if (!Application.isPlaying)
    6.                 return;
    7. #endif
    8.  
    9.             m_AlphaTweenRunner = new TweenRunner<FloatTween>();
    10.             m_AlphaTweenRunner.Init(this);
    11.  
    12.             if (m_CaptionImage)
    13.                 m_CaptionImage.enabled = (m_CaptionImage.sprite != null);
    14.  
    15.             if (m_Template)
    16.                 m_Template.gameObject.SetActive(false);
    17.         }
    18.  
    19.         protected override void Start()
    20.         {
    21.             Debug.Log("Now I've started: " + this.GetType().Name);
    22.             base.Start();
    23.  
    24.             RefreshShownValue();
    25.         }
    When run, the first thing I see is "Now I've started: TMP_Dropdown" in the console. Under what conditions will a component have its Start() method called but not Awake()?

    (The Awake and Start debug lines both show up when I exit play mode.)

    This is in 2019.4.10f1.
     
  2. VishwasGagrani

    VishwasGagrani

    Joined:
    May 12, 2018
    Posts:
    84
    Did you try shifting the component's code in Start( ) instead of Awake() ?
    It is possible that a heavy component may take time to be fully used inside Awake.

    Code (CSharp):
    1. protected override void Awake()
    2.         {
    3.             Debug.Log("Okay! I'm awake: " + this.GetType().Name);
    4. #if UNITY_EDITOR
    5.             if (!Application.isPlaying)
    6.                 return;
    7. #endif
    8.             m_AlphaTweenRunner = new TweenRunner<FloatTween>();
    9.         }
    10.         protected override void Start()
    11.         {
    12.             m_AlphaTweenRunner.Init(this);
    13.             if (m_CaptionImage)
    14.                 m_CaptionImage.enabled = (m_CaptionImage.sprite != null);
    15.             if (m_Template)
    16.                 m_Template.gameObject.SetActive(false);
    17.  
    18.             Debug.Log("Now I've started: " + this.GetType().Name);
    19.             base.Start();
    20.             RefreshShownValue();
    21.         }
     
  3. wx3labs

    wx3labs

    Joined:
    Apr 5, 2014
    Posts:
    77
    This isn't my code, it's Unity's, so I'd prefer not to rely on modifications to it.

    I was under the impression that Awake should get called before Start on a particular component, independent of the component size.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,727
    Yes, this is true. Component size has NOTHING to do with it.

    Unity will call Awake() before Unity will call Start(), that's for sure. OTHER code might call either of those functions if they are public.

    BUT... there is no guarantee that someone calls
    base.Awake()
    and this can be a HUGE source of errors such as the one you are seeing.

    In fact, look above! You're NOT calling
    base.Awake()
    even though your .Awake() is an
    override
    .

    This is why deriving from MonoBehaviors is a bad idea: the general "view" of Unity developers does not anticipate people inheriting their code, and as a consequence they don't generally think that way, so hierarchal message passing is often skipped or done incorrectly.

    Also, if you are making a public reference of a base class Foo(), but you are actually dragging an instance of Bat() (which derives from Foo()) into the inspector, over the years and various versions of Unity, I have seen either Foo.Awake() get called, or else Bat.Awake() getting called.

    This would be definitely a Bad Thing(tm) and an ambiguity you want to avoid.
     
    Ryiah and Joe-Censored like this.
  5. wx3labs

    wx3labs

    Joined:
    Apr 5, 2014
    Posts:
    77
    Thanks for the reply. I should stress again: this is not my code. It is in a package provided and supported by Unity:

    https://docs.unity3d.com/Manual/com.unity.textmeshpro.html

    This is a widely used component that works for most people, so I'm assuming there is something specific to my project that is causing this odd behavior. I have not modified it except for adding those debug lines.
     
  6. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,836
    If you're getting problems with unmodified TMP scripts, you may want to post in the subforum for UGUI and TextMeshPro:
    https://forum.unity.com/forums/ugui-textmesh-pro.60/

    When last I frequented that forum, the creator of TextMeshPro seemed to be fairly active there.
     
    wx3labs likes this.
  7. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I found this thread when looking for the same issue. I'm also seeing very strange behaviour of the builtin TMP_Dropdown class. If I SetActive(false) the GameObject the dropdown is on during Awake, the Dropdown will receive the Awake call, but if I disable the GameObject in Start, the dropdown's Awake isn't called.

    I'll try to reproduce this in a test project and will submit a bug report, but if anyone has an idea what's going on or how to avoid it, please let me know. :)