生命周期
生命周期图
在使用 unity 引擎开发之前,你一定要先了解它脚本的生命周期,这样方便开发,更方便你阅读别人的代码,话不多说直接开始。
unity 中定义了很多非常重要的事件函数,先来一个图,图中详细介绍了 unity 中所有重要的事件函数,这个图是从 untiy 官网文档中复制下来的 这里我使用的 unity 版本是 2017.4.30 版本的。
生命周期流程细节分析
介绍这个生命周期要分两部分,编辑期间,运行期间:因为,这两部分中会分别运行一些方法,我们需要根据实际情况去分析。
我这里只介绍一些重要的部分,不会每一个去分析。
编辑期间执行的方法
1.初始化:
- Reset() 重置函数,
编辑期当脚本首次赋值给游戏对象时触发一次
,只在编辑期间,执行一次
,如果你在运行期间将一个脚本动态加载到一个对象上,这个函数也是不会执行的;
2.更新:
- OnDrawGizmos() 函数,这个函数在编辑期间和在运行期间调用频率不同,在编辑期间,它不是像 Update 那种每一帧更新,
只在 Scene 视图打开的时候,在这个视图下操作,会调用这个函数
,在只打开 Game 视图中,操作物体,不会调用这个函数,所以在编辑期间和游戏运行期间,只要你打开了 Scene 视图,就会调用这个函数。
打开 scene 视图,随便移动图中 正方体,该函数一直在被调用,不移动的时候,就会停下来,只要你的鼠标在上面动了,它就会一直调用,直到你不操作这个视图,这个函数就不会调用:
只打开 Game 视图,随便更改坐标,材质等,都不会调用这个函数:
如果要想在编辑器下执行以下更新函数: Update,LateUpdate,OnWillRenderObject,OnGUI 等,可以在自定义类前加入 “[ExecuteInEditMode]”
即可,如下图,具体实现顺序,如生命周期图所示,或者和下面执行阶段中执行顺序相同,这里不过多介绍,建议自己多做尝试。
运行期间执行的方法
1.初始化:
-
Awake() 唤醒函数,
最先执行的函数
,用于优先级最高的事件处理,执行一次
;(如果说,一开始对象就没有激活,一直处于一个隐藏的状态,在游戏运行的时候,是不会触发 Awake 的,直到第一次激活这个对象才会触发这个函数,后序连续启用禁用都不会再触发这个函数了,小心踩坑,书写代码一定要注意这种情况)
(之前项目中遇到一个设计缺陷:一个接口在对某个对象中的某个组件的初始值做了初始化,但是这个对象还没有被激活过,所以当这个对象第一次被激活的时候,因为那个组件走了 Awake 导致之前初始化的数据被重置了,然后没有到达预期的效果
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:调用
挂载对象已激活,脚本已激活:调用 -
OnEnable() 启动函数,
与 OnDisable() 配套结合
,当脚本启用的时候触发,随着脚本的不断启用和禁用来回切换,执行多次
;
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:不调用
挂载对象已激活,脚本已激活:调用 -
OnApplicationPause(bool pause) 函数,这个函数主要发生在 “切后台”,当你打开别的 app 时,这个函数会自动调用,并且 “pause 为 true”,当你再切回来的时候,这个函数自动调用,并且 “pause 为 false”,
可以执行多次
;在引擎刚开始运行时,以下情况也会自动调用一次 “pause 为 false”,正常情况下是在 OnEnable 函数之后,在游戏运行以后,发生如下情况,都不会调用。
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:调用
挂载对象已激活,脚本已激活:调用 -
Start() 开始函数,一般用于给脚本字段初始值使用,
执行一次
,注意这里的 Start 没有 On 作为前缀;
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:不调用
挂载对象已激活,脚本已激活:调用游戏运行时,挂载对象已激活,脚本也激活,函数运行的顺序如下:
游戏运行时,挂载对象已激活,脚本未激活,函数运行的顺序如下:
一帧更新开始
更新中的所有函数都遵循以下规则,OnDrawGizmos 这个函数除外:
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:不调用
挂载对象已激活,脚本已激活:调用
2.物理更新
- FixedUpdate() 固定更新函数,以默认 0.02s 的时钟频率执行,常用于物理学模拟中处理刚体的移动等,
每秒执行多次
,如果固定帧步长小于实际帧更新时间,那么每一帧的物理周期中,这个函数会被调用多次;
3.输入事件
这里与其相关函数事件较多,不做特别分析。
4.逻辑更新
- Update() 更新函数,执行的频率不固定,与计算机当前性能消耗成反比,常用于逻辑计算,
每秒执行多次
; - LateUpdate() 后更新函数,在上面两个更新函数之后运行,常用于摄像机的控制情形中,
每秒执行多次
;
5.场景渲染
- OnWillRenderObject() 函数,如果对象可见,每个照相机调用一次(这是官方解释)。通常对于一些确定要渲染的对象,在正式渲染前再做一些特殊处理,比如裁剪,材质的重置等。
6.线框渲染
- OnDrawGizmos() 函数,在 Scene 视图打开的时候每一帧更新,和在 编辑器模式下调用的频率不同。
如果打开了 Game 视图:
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:不调用
挂载对象已激活,脚本已激活:不调用
如果打开了 Scene 视图:
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:每一帧调用
挂载对象已激活,脚本已激活:每一帧调用
7.GUI 渲染
- OnGUI() 图形绘制函数,绘制系统UI界面,
每秒执行多次
,每一帧更新多次;
一帧更新结束
8.游戏退出
-
OnApplicationQuit() 函数,在运行结束的时候调用,
执行一次
;
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:调用
挂载对象已激活,脚本已激活:调用 -
OnDisable() 脚本禁用函数,
与 OnEnable() 配套结合
,当脚本被禁用的时候触发,随着脚本的不断启用和禁用来回切换,执行多次
,如果脚本在游戏退出时一直处于 “激活”状态,那么游戏退出的时候就会自动调用这个函数;
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:不调用
挂载对象已激活,脚本已激活:调用 -
OnDestory() 销毁函数,本脚本所属游戏对象销毁的时候执行,
执行一次
,在游戏退出时未被销毁的对象(包括激活对象,和未激活对象),就会自动调用;
挂载对象未激活:不调用
挂载对象已激活,脚本未激活:调用
挂载对象已激活,脚本已激活:调用
在游戏结束的时候,挂载对象已激活,脚本已激活,分别执行以下函数,并且执行顺序如下:
在游戏结束的时候,挂载对象已激活,脚本未激活,分别执行以下函数,并且执行顺序如下:
总结
(这里 FixedUpdate 等每秒执行多次的函数,因为执行次数太多,我代码中限制了打印次数)