再议Unity3D中的Awake(),OnEnable()和Start()

引言
近来遇到了一个问题,排查到最后,发现问题的原因在于,对于Unity原生函数执行顺序的理解还不到位。之前转载过一篇介绍Unity原生函数执行顺序的文章Unity3D中脚本的执行顺序和编译顺序
单纯的讨论一个GameObject的Awake在Start函数执行是没什么实际意义的。当遇到动态加载对象,或者相互引用时,情况要复杂一些。
官方介绍
First Scene Load
These functions get called when a scene starts (once for each object in the scene).
● Awake: This function is always called before any Start functions and also just after a prefab is instantiated. (If a GameObject is inactive during start up Awake is not called until it is made active.)
● OnEnable: (only called if the Object is active): This function is called just after the object is enabled. This happens when a MonoBehaviour instance is created, such as when a level is loaded or a GameObject with the script component is instantiated.
● OnLevelWasLoaded: This function is executed to inform the game that a new level has been loaded.
Note that for objects added to the scene, the Awake and OnEnable functions for all scripts will be called before Start, Update, etc are called for any of them. Naturally, this cannot be enforced when an object is instantiated during gameplay.
Before the first frame update
● Start: Start is called before the first frame update only if the script instance is enabled.
For objects added to the scene, the Start function will be called on all scripts before Update, etc are called for any of them. Naturally, this cannot be enforced when an object is instantiated during gameplay.
可以看到Awake和OnEnable是在GameObject instantiate阶段被调用的。而Start是在Update第一次执行前被调用的。
测试
测试用例:
写了两段脚本,第一段脚本StartGo.cs挂在默认对象上,通过点击场景上的按钮来动态创建第二个对象,其上挂载着第二段脚本DynamicGo.cs。
StartGo.cs

using UnityEngine;
using System.Collections;

public class StartGo : MonoBehaviour {

    private bool operateOnce = false;
    void Awake()
    {
        Debug.Log("StartGo Awake, frame: " + Time.frameCount);
    }
    void OnEnable()
    {
        Debug.Log("StartGo OnEnable, frame: " + Time.frameCount);
    }
    // Use this for initialization
    void Start () 
    {
        Debug.Log("StartGo Start, frame: " + Time.frameCount);
    }

    // Update is called once per frame
    void Update () 
    {
        if (!operateOnce)
        {
            Debug.Log("StartGo Update, frame: " + Time.frameCount);
            operateOnce = true;
        }
    }

    void OnGUI()
    {
        if (GUI.Button(new Rect(100, 100, 200, 30), "Create Dynamic Go"))
        {
            Debug.Log("Click Create Dynamic Go, frame: " + Time.frameCount);
            GameObject go = Resources.Load("DynamicGo") as GameObject;
            GameObject.Instantiate(go);
            Debug.Log("Instantiate Finished, frame: " + Time.frameCount);
        }
    }
}

DynamicGo.cs

using UnityEngine;
using System.Collections;

public class DynamicGo : MonoBehaviour {
    private bool operateOnce = false;
    void Awake()
    {
        Debug.Log("DynamicGo Awake, frame: " + Time.frameCount);
    }
    void OnEnable()
    {
        Debug.Log("DynamicGo OnEnable, frame: " + Time.frameCount);
    }
    // Use this for initialization
    void Start () 
    {
        Debug.Log("DynamicGo Start, frame: " + Time.frameCount);
    }

    // Update is called once per frame
    void Update () 
    {
        if (!operateOnce)
        {
            Debug.Log("DynamicGo Update, frame: " + Time.frameCount);
            operateOnce = true;
        }

    }
}

运行结果:
这里写图片描述这里写图片描述这里写图片描述
1.其中StartGo.cs的Start信息在OnEnable的下一帧打印出来,而DynamicGo.cs的Start信息与OnEnbale在同一帧打印出来。
2.通过查看DynamicGo的堆栈调用,可以看到OnEnable与Awake是在UnityEngine.Object:Instantiate阶段被调用的。而Start是在Update执行之前在会触发。
结论:
OnEnable与Awake是在GameObject实例化阶段被调用的。
Start可能与OnEnable在同一帧执行,也可能在OnEnable的下一帧执行。

  • 5
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值