事件函数执行顺序
在 Unity 脚本中,有大量的事件函数以特定的顺序被执行。执行顺序描述如下:
编辑器
Reset
当第一次把脚本绑定到对象上,或者使用了 Reset 命令时,该事件被触发,用以初始化脚本的属性。
加载第一个场景
当某个场景开始时,下面的事件被触发(场景中的每个对象都会执行一次):
Awake
该函数总是在所有 Start 函数之前被调用,并且只会在某个 prefab 被实例化之后才会被调用。(如果一个 GameObject 在启动时是非激活状态,那么 Awake 函数不会被调用,直到这个 GameObject 处于激活状态。)
OnEnable
(只有对象处于激活状态才会被调用)该函数在对象处于可用状态之后被调用。当一个 MonoBehaviour 实例被创建时,就会调用该函数。例如关卡加载完成、某个带有脚本组件的 GameObject 被实例化后。
OnLevelWasLoaded
该函数在某个新关卡加载完成后被执行,用来向游戏通知新关卡已经被载入。
请注意,对于场景 scene 中已有对象上附加的脚本组件,函数 Awake 和 OnEnable 将在所有 Start、Update 等函数之前被调用。当然,如果某个对象是游戏运行时实例化的,那么不遵循这条原则。
第一帧更新之前
Start
该函数在第一帧更新之前被调用,前提是该脚本实例必须是可用的。
对于场景 scene 中已有对象上附加的脚本组件,函数 Start 在 Update 等函数之前被调用。当然,如果某个对象是游戏运行时实例化的,那么不遵循这条原则。
帧间
OnApplicationPause
如果游戏处于暂停状态,该函数在某一个帧的末尾被调用,也就是说,是在正常帧(更新)之间被调用。当 OnApplicationPause 被调用后,一个特殊的帧被创建,这样游戏可以显示暂停状态的图形。
帧更新顺序
当你跟踪游戏的逻辑、交互、动画、摄像机位置等时,也有几个事件可供使用。通常我们是在 Update 函数中执行大部分任务,但也可以使用其他的函数。
FixedUpdate
通常,FixedUpdate 比 Update 调用的更频繁。如果帧率很低,可以在每一帧上多次调用 FixedUpdate;如果帧率很高,FixedUpdate 更本不会被调用。调用 FixedUpdate 之后,所有的物理计划和更新会立即生效,如果在 FixedUpdate 中执行位移计算,你就不需要基于 Time.deltaTime 来计算。因为 FixedUpdate 基于一个可靠的计时器,与帧率无关。
Update
每帧调用一次 Update。对于帧更新来说,Update 是主要的任务承载函数。
LateUpdate
LateUpdate 在 Update 完成之后被调用,每帧调用一次。当 LateUpdate 开始执行时,Update 中执行的所以计算都已完成。如果你在 Update 中移动和旋转角色,那么你可以在 LateUpdate 中移动和旋转摄像机。这样,在摄像机跟随角色的位置之前,可以确保角色的移动已经完成。
渲染
OnPreCull
在摄像机对场景进行 Culling 之前被调用。Culling 确定了哪些对象对于摄像机是可见的。
译注 Unity中的优化技术
OnBecameVisible/OnBecameInvisible
当某个对象对于任意摄像机变为可见或不可见时被调用。
OnWillRenderObject
为每个摄像机调用一次,如果该对象是可见的。
OnPreRender
在摄像机开始渲染场景之前被调用。
OnRenderObject
在常规场景渲染完成之后被调用。此时,你可以使用类 GL 或 Graphics.DrawMeshNow 绘制自定义的几何体。
OnPostRender
当某个摄像机完成渲染场景之后被调用。
OnRenderImage
在场景渲染完成之后被调用,用于图像后处理,请查看 ImageEffects。
OnGUI
用于响应 GUI 事件,每一帧会多次调用。首先处理 Layout 和 Repaint 事件,然后是 Layout,以及每次用户输入触发的 keyboard/mouse 事件。
OnDrawGizmos
用于在场景视图中绘制 Gizmos,使之可视化。
协同程序
通常,协同更新在函数 Update 返回后运行。一个协同程序是一个可以暂停运行过程的函数,当给定的 YieldInstruction 完成时继续执行。协同程序的不同用法如下:
yield
下一帧中的所有 Update 函数被调用后,协同程序将继续执行。
yield WaitForSeconds
当前帧的所有 Update 函数被调用后,并且延迟给定的时间,协同程序将继续执行。
yield WaitForFixedUpdate
所有脚本的 FixedUpdate 函数被调用后,协同程序将继续执行。
yield WWW
网络下载完成后,协同程序将继续执行。
yield StartCoroutine
将协同程序串联起来,等待 MyFunc 执行完成后,继续链式执行。
当对象被销毁时
OnDestroy
在对象存在的最后一帧,当所有帧更新都完成后,该函数被调用(该对象可能因为调用了 Object.Destroy 而被销毁,也可能随着场景的关闭而销毁)。
当退出时
这些函数会在场景中的所有激活对象上调用。
OnApplicationQuit
在应用程序退出前,在所有游戏对象调用该方法。如果是在编辑器中,那么当用户停止游戏模式时,该函数被调用。
OnDisable
当游戏对象的行为变为禁用或不活动时,该函数被调用。
脚本生命周期流程图
下图总结了脚本生命周期中事件函数的执行顺序和重复周期。