Unity脚本执行顺序
在Unity中,要控制Unity的脚本执行顺序,Unity引擎本身已经有了一个脚本排序。这个排序在编辑器中可以编辑并设置。它里面带有默认的,根据优先级来排定执行顺序。若没有在排序的均在default time排序的间隙随机执行。也就是说,在在default time 以上列表中的优先级总是高于其他排序。
在Unity中,继承于MonoBehaviour 的类,有几个Unity3D自带的事件函数按照预定的顺序执行作为脚本执行。
我们可以做一些测试来验证以及学习他们的执行顺序。
测试1.0:
创建一个空物体A,添加脚本ScriptA,代码如下:
运行代码可以得到如下结果:
结束程序可以得到如下结果:
上述试验可以得出简单结论:
Awake -> OnEnable -> Start -> (FixedUpdate -> Update -> LateUpdate) -> OnDisable -> OnDestroy
其中,括号内的是一直不断执行的。
测试1.1:
我们做点简单的手脚,先将不断循环的内容屏蔽(FixedUpdate 、 Update 、 LateUpdate),然后在运行后,将此物体设为不可见(模拟 SetActive(false)),再将物体设为可见(模拟 SetActive(true)),结果如下:
说明了 SetActive(false) 会执行代码中的 OnDisable,SetActive(true) 会执行代码中的OnEnable。
测试1.2:
依然先将循环的内容屏蔽,然后再运行。运行时先将脚本取消选用(模拟 enabled = false),再将脚本选用(模拟 enabled = true),结果如下:
说明了执行的内容和SetActive 一样。
测试2.0:
新建脚本ScriptB 和 ScriptC。代码和 ScriptA 一样,屏蔽了循环的内容。都挂在物体A上。
结果如下:
结论如下:
最底下的脚本先执行,而Awake和OnEnable的执行顺序交替进行,Start最后,流程如下
C.Awake -> C.OnEnable -> B.Awake -> B.OnEnable -> A.Awake -> A.OnEnable -> C.Start -> B.Start -> A.Start
测试2.1:
我们先选择单击一脚本,如SriptA。如下图:
再点击上图红色箭头指示的Execution Order。出现如下界面:
点击箭头指示的“加号”,依次添加ScriptA、ScriptB、ScriptC,并Apply。如下所示:
再次运行程序,结果如下:
我们清楚的看到,脚本执行的顺序改变了,按照我们在Execution Order设置的顺序执行了。
测试2.2 :
在物体A上仅挂载脚本ScriptD,在ScriptD中加载ScriptE和销毁ScriptE。代码如下:
ScriptD
ScriptE
结果如下:
ScriptE.Awake 和 ScriptE.OnEnable 方法应该是在执行scriptE = gameObject.AddComponent(); 这条语句的时候就已经被调用了。而ScriptE.Start在之后再执行。
同理: ScriptE.OnDisable 方法应该是在执行 GameObject.Destroy(scriptE); 时就被调用了。而ScriptE.OnDestroy 则是更后一些。
更多:
脚本更为详细的执行顺序。
各函数描述:
Awake:当一个脚本实例被载入时Awake被调用。Awake用于在游戏开始之前初始化变量或游戏状态。在脚本整个生命周期内它仅被调用一次.Awake在所有对象被初始化之后调用,所以你可以安全的与其他对象对话或用诸如 GameObject.FindWithTag 这样的函数搜索它们。每个游戏物体上的Awke以随机的顺序被调用。因此,你应该用Awake来设置脚本间的引用,并用Start来传递信息Awake总是在Start之前被调用。它不能用来执行协同程序。
OnEnable:当对象变为可用或激活状态时此函数被调用。
Start:Start仅在Update函数第一次被调用前调用。它和Awake的不同是Start只在脚本实例被启用时调用。你可以按需调整延迟初始化代码。Awake总是在Start之前执行。这允许你协调初始化顺序。在所有脚本实例中,Start函数总是在Awake函数之后调用。
FixedUpdate:当MonoBehaviour启用时,其 FixedUpdate 在每一帧被调用。处理Rigidbody时,需要用FixedUpdate代替Update。例如:给刚体加一个作用力时,你必须应用作用力在FixedUpdate里的固定帧,而不是Update中的帧。(两者帧长不同)
Update:当MonoBehaviour启用时,其Update在每一帧被调用。Update是实现各种游戏行为最常用的函数。为了获取自最后一次调用Update所用的时间,可以用Time.deltaTime。这个函数只有在Behaviour启用时被调用。实现组件功能时重载这个函数。
LateUpdate:当Behaviour启用时,其LateUpdate在每一帧被调用。LateUpdate是在所有Update函数调用后被调用。这可用于调整脚本执行顺序。例如:当物体在Update里移动时,跟随物体的相机可以在LateUpdate里实现。为了获取自最后一次调用LateUpdate所用的时间,可以用Time.deltaTime。这个函数只有在Behaviour启用时被调用。实现组件功能时重载这个函数。
OnDisable:当对象变为不可用或非激活状态时此函数被调用。当物体被销毁时它将被调用,并且可用于任意清理代码。当脚本编译完成之后被重加载时,OnDisable将被调用,OnEnable在脚本被载入后调用。
OnDestroy:当MonoBehaviour将被销毁时,这个函数被调用。OnDestroy只会在预先已经被激活的游戏物体上被调用。