首页 > 代码库 > Unity3D中脚本的执行顺序和编译顺序
Unity3D中脚本的执行顺序和编译顺序
在Unity中可以同时创建很多脚本,并且可以分别绑定到不同的游戏对象上,它们各自都在自己的生命周期中运行。与脚本有关的也就是编译和执行啦,本文就来研究一下Unity中脚本的编译和执行顺序的问题。
先说一下执行顺序吧。
官方给出的脚本执行顺序如下图:
我们可以做一个小实验来测试一下:
在Hierarchy视图中创建三个游戏对象,在Project视图中创建三条脚本,如下图所示,然后按照顺序将脚本绑定到对应的游戏对象上:
三条脚本的代码完全一样,只是做了一点名称上的区分:
1 using System.Collections; 2 3 public class Scring0 : MonoBehaviour 4 { 5 void Awake() 6 { 7 Debug.Log("Script0 ======= Awake"); 8 } 9 10 bool isUpdate = false;11 void Update()12 {13 if(!isUpdate)14 {15 Debug.Log("Script0 ======= Update");16 isUpdate = true;17 }18 }19 20 bool isLateUpdate = false;21 void LateUpdate()22 {23 if(!isLateUpdate)24 {25 Debug.Log("Script0 ======= LateUpdate");26 isLateUpdate = true;27 }28 }29 }
播放游戏,看看它们的执行顺序。如下图所示,Awake、Update、LateUpdate,无论运行游戏多少次,它们的执行顺序是完全一样的。
接着我们再做一个测试,把Script0的Update方法注释掉!!
1 using System.Collections; 2 3 public class Scring0 : MonoBehaviour 4 { 5 void Awake() 6 { 7 Debug.Log("Script0 ======= Awake"); 8 } 9 10 // bool isUpdate = false;11 // void Update()12 // {13 // if(!isUpdate)14 // {15 // Debug.Log("Script0 ======= Update");16 // isUpdate = true;17 // }18 // }19 20 bool isLateUpdate = false;21 void LateUpdate()22 {23 if(!isLateUpdate)24 {25 Debug.Log("Script0 ======= LateUpdate");26 isLateUpdate = true;27 }28 }29 }
再次运行游戏,看看它的结果。脚本的执行顺序和以前完全一样,Script0即便删除掉了Update方法,但是它也不会直接执行LateUpdate方法,而是等待Script1和Script2中的Update方法都执行完毕以后,再去执行所有的LateUpdate方法。
通过这两个例子,我们就可以很清楚地断定,Unity后台是如何执行脚本的了。每个脚本的Awake、Start、Update、LateUpdate、FixedUpdate等等,所有的方法在后台都会被汇总到一起:
1 后台的Awake()2 {3 脚本0中的Awake();4 脚本1中的Awake();5 脚本2中的Awake();6 }
后台的方法Awake、Update、LateUpdate等等,都是按照顺序,等所有游戏对象上脚本中的Awake执行完毕之后,再去执行Start、Update、LateUpdate等方法的。
1 后台的Update()2 {3 脚本0中的Update();4 脚本1中的Update();5 脚本2中的Update();6 }
然后我们来看看这样一种情况:在脚本0的Awake方法中创建一个立方体对象,然后在脚本2的Awake方法中去获取这个立方体对象。代码如下:
1 脚本0的代码: 2 using UnityEngine; 3 using System.Collections; 4 5 public class Script2 : MonoBehaviour 6 { 7 void Awake() 8 { 9 GameObject.CreatePrimitive(PrimitiveType.Cube);10 }11 }12 13 脚本2的代码:14 using UnityEngine;15 using System.Collections;16 17 public class Script0 : MonoBehaviour18 {19 void Awake()20 {21 GameObject go = GameObject.Find("Cube");22 Debug.Log(go.name);23 }24 }
如果脚本的执行顺序是先执行Script0,然后再执行Script2,那么Script2中的Awake就可以正确地获取到该立方体对象;可是如果脚本的执行顺序是先执行Script2,然后是Script0,那么Script2肯定会报空指针错误的。
那么实际项目中的脚本会非常多,它们的先后执行顺序我们谁也不知道(又说是按照栈结构来执行的,即后绑定到游戏对象上的脚本先执行。这一点值得研究)。但一般的,建议在Awake方法中创建游戏对象或Resources.Load(Prefab)对象,然后在Start方法中去获取游戏对象或者组件,这样就可以确保万无一失了。
另外,Unity也提供了一个方法来设置脚本的执行顺序,在Edit -> Project Settings -> Script Execution Order菜单项中,可以在Inspector面板中看到如下图所示:
点击右下角的"+"将弹出下拉窗口,包括游戏中的所有脚本。脚本添加完毕后,可以用鼠标拖动脚本来为脚本排序,脚本名后面的数字也越小,脚本越靠上,也就越先执行。其中的Default Time表示没有设置脚本的执行顺序的那些脚本的执行顺序。
Unity3D中脚本的执行顺序和编译顺序