[Unity] 生命周期相关

生命周期相关。

脚本的生命周期:

Unity脚本有一套完整的生命周期,脚本需要挂在任意游戏对象上,并且同一个游戏对象可以挂不同的脚本,各脚本执行自己的生命周期,它们可以互相组合并且互不干预。生命周期中的所有方法都是Unity系统自己回调的,不需要手动调用,主要有编辑脚本、初始化、物理碰撞事件、更新回调、渲染和销毁等。学习脚本的生命周期之前,我们不得不引用文档中非常经典的一张图,它完整的描述了脚本的生命周期:

第一个场景加载:

这些函数将在场景开始加载时调用。(场景中的每个物体仅调用一次)

  • Awake:这个方法总是在在任何开始方法之前调用(可以理解成最先调用吧?),并且在一个prefab刚被实例化后就调用。(如果一个游戏物体在开始时是不活跃的(inactive)则将不会调用awake函数,直到其变为活跃。)
  • OnEnable:(仅在物体为活跃(active)状态调用):这个函数仅在一个物体变为有效(enabled)后调用。这通常发生在一个MonoBehavior实例创建时,例如在一个场景加载时或者一个持有脚本组件的游戏物体被实例化时。
  • OnLevelWasLoaded:这个函数用来通知游戏逻辑一个新的场景已经被加载完。

注意:对于加到场景中的物体来说,Awake和OnEnable方法将在所有脚本的任何类似于Start、Update等方法被调用之前调用。自然的,这些方法也不能在游戏进行中强制调用。

编辑器:

  • Reset:Reset被调用于第一次将脚本绑定到物体上时初始化脚本属性,或者在Reset指令被触发时调用。

在帧之间:

  • OnApplicationPause::这个方法在检测到暂停的帧的末尾调用,在正常帧更新间有效?之后将会发出一个额外的帧。调用OnApplicationPause以允许游戏显示指示暂停状态的图形。

更新顺序:

当你追踪游戏逻辑和交互、动画、相机位置等,你可以使用几个不同的事件。常见的模式是在Update函数中执行大多数任务,但也可以使用其他功能。

  • FixedUpdate:FixedUpdate函数通常要比Update函数调用的更为频繁,会按照设置的时间固定频率来循环更新。如果帧速率低,则可以每帧调用多次,如果帧速率高,则可以不在帧之间调用。所有物理计算和更新在FixedUpdate之后立即发生。在FixedUpdate中应用移动计算时,不需要乘以Time.deltaTime。这是因为FixedUpdate在可靠的定时器上调用,与帧速率无关。
  • Update:Update每帧调用一次。它是帧更新的主要功能。
  • LateUpdate:LateUpdate每帧调用一次,但在Update执行结束之后。在LateUpdate开始时,在Update中执行的任何计算都应该已经完成。LateUpdate的一个常见用途是实现跟随的第三人称相机。如果你将角色移动放在Update中执行,那么你可以将所有的相机移动和旋转计算放在LateUpdate中执行。这将确保角色在摄像机跟踪其位置之前完全移动。

总体来说,Update()和LateUpdate()属于立即更新,更新之间的频率是不固定的,比如某一帧有一个耗时操作的时候,就会影响到下一帧更新的时间,所以对更新频率要求比较稳定的物理系统就不太适合在这里处理更新。

FixedUpdate()虽然是固定更新,但是其实也是相对固定的,比如某一帧耗了好几秒,它依然会卡住。不过正常的程序要优化耗时操作,小范围的帧率波动是正常的,可以让它更新的时间间隔稍微长一点,这样它的更新是比较平滑的。在实际的开发中,例如以秒为单位的倒计时,并不需要每一帧去判断时间,所以用FixedUpdate()就再合适不过了。

动画更新循环:

这些方法和Profiler Markers在Unity评估(?)动画系统时会调用。

(暂略)

有用的profile markers:

(暂略)

渲染:

  • OnPreCull:在相机剔除场景之前调用。剔除确定相机可以看到哪些对象。在剔除之前调用OnPreCull。
  • OnBecameVisible/OnBecameInvisible:当对象变得对任何相机可见/不可见时调用。
  • OnWillRenderObject:如果对象可见,则为每个摄像机调用一次。
  • OnPreRender:在相机开始渲染场景之前调用一次。
  • OnRenderObject:在完成所有常规场景渲染后调用。您可以使用GL类或Graphics.DrawMeshNow来绘制自定义几何体。
  • OnPostRender:在相机完成渲染场景后调用。
  • OnRenderImage:在场景渲染完成后调用以允许对图像进行后处理,请参阅后处理效果。
  • OnGUI:响应GUI事件,每帧调用多次。首先处理Layout和Repaint事件,然后为每个输入事件处理Layout和keyboard / mouse事件。
  • OnDrawGizmos:用于在场景视图中绘制Gizmo以进行可视化。

协程:

正常的协程在Update函数返回后更新。协程是一个可以暂停执行(yield)直到给定的YieldInstruction完成的函数。以下是协程的不同用处:

  • yield:在下一帧调用所有Update函数后,协程将继续。
  • yield WaitForSeconds:在为帧调用了所有的Update函数后,协程在指定的延迟时间后继续。
  • yield WaitForFixedUpdate:在所有脚本中的的所有FixedUpdate执行后继续协程。
  • yield WWW:在一个WWW类的下载完成之后执行协程。
  • yield StartCoroutine:链接协程,并将等待MyFunc协程首先完成。

当物体被销毁时:

  • OnDestroy:在对象存在的最后一帧的所有帧更新之后调用这个函数。(该对象可能在相应Object.Destory或者场景闭合时被销毁)。

当退出时:

在场景中的所有活动对象上调用这些函数:

  • OnApplicationQuit:在退出应用程序之前,将在所有游戏对象上调用此函数。在编辑器中,当用户停止播放模式时调用它。
  • OnDisable:当行为被禁用或处于非活动状态时,将调用此函数。