• 事件函数执行顺序
    • 编辑器
    • 加载第一个场景
    • 第一帧更新之前
    • 帧间
    • 帧更新顺序
    • 渲染
    • 协同程序
    • 当对象被销毁时
    • 当退出时
    • 脚本生命周期流程图

    事件函数执行顺序

    在 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

      当游戏对象的行为变为禁用或不活动时,该函数被调用。

    脚本生命周期流程图

    下图总结了脚本生命周期中事件函数的执行顺序和重复周期。

    事件函数执行顺序 - 图1