Unity3D中脚本的生命周期是按照预先定义好的事件函数的执行流程来演化的,具体流程如下:
Editor模式下Reset:
当脚本第一次被挂到GameObject上或用户点击Reset按钮时,Reset被调用初始化脚本属性,最常用于在Inspector视图中呈现好的默认值。
加载第一个场景First Scene Load:
场景启动时会对场景中的每个对象执行一遍如下事件函数:
- Awake:游戏启动之前初始化任何变量和游戏状态,仅在脚本生命周期中调用一次,不能做协程,Start函数之前以及预制物体实例化后被调用。GameObject之间Awake的调用没有先后顺序规定,因而可以利用Awake建立脚本之间的引用,再使用Start 来回传递信息。(对于C#、Boo用户,当构造时组件序列化状态没有定义,就应该使用Awake代替构造函数初始化)。
- OnEnable:只有GameObject是激活状态下才被调用,通常发生于MonoBehaviour实例被创建。
第一帧更新之前Before the First Frame Update:
如果脚本实例化被启用,则Start函数在第一帧更新之前被调用,仅在脚本生命周期中调用一次。不论脚本enabled与否,Awake都会调用;假如初始化期间脚本disabled,则Start就不会与Awake在同一帧被调用。Awake和OnEnable一定是在Start之前调用(好处是:object A实例化代码依赖于object B实例化,B实例化就在Awake阶段完成,A实例化就在Start阶段完成)。
帧之间In Between Frames:
若暂停被检测到,当前帧执行后就调用OnApplicationPause函数,在正常的帧更新之间调用是有效的。在OnApplicationPause被调用后,增加额外的一帧来显示图像表明暂停状态。OnApplicationPause 可以是协程,假如其作为协程来执行,在初始化帧期间会被 用到两次:第一次用作前期通知,第二次发生在正常的协程更新步骤中。
更新顺序Update Order:
当想要追踪游戏逻辑、动画、相机位置等,可以在更新事件函数中执行这些任务,调用的顺序为FixedUpdate、Update、LateUpdate,当然脚本中不是必须三者都包含在内。三者不同见Unity3D的事件函数。协程在所有Update函数完成后执行;若在LateUpdate中开启了一个协程,它将在LateUpdate之后渲染之前也会被调用。
渲染Rendering:
- OnPreCull: 在相机剔除场景前被调用,剔除决定了哪些物体在相机中是可见的。假如要修改相机的可视化参数(比如FOV,Transform等),就应该在这个函数中进行修改,此后场景中GameObject的可见性就取决于相机的参数了。
- OnBecameVisible/OnBecameInvisible:当GameObject在任何相机中变得可见/不可见时被调用,该消息被发送到任何挂在渲染器上的脚本。使用这两个函数可以避免不必要的计算,仅当GameObject可见时才进行相应的计算。它们可以是协程,简单地使用yield 即可,当在编辑器中运行时,场景视图摄像机也会导致它们被调用。
- OnWillRenderObject:如果物体可见并且脚本是enabled,在渲染每个经过剔除操作之后的物体之前,它将为每个相机调用一次。
- OnPreRender:仅当脚本挂在相机上并且enabled时,则在相机开始渲染场景之前被调用。假如在这个函数中修改了相机的可视化参数(比如FOV),那么这些参数只会在下一帧中起到作用。该函数可以是协程,仅在函数中使用yield即可。
- OnRenderObject:在所有固定场景渲染之后被调用,此时你可以使用GL类函数或者Graphics.DrawMeshNow来画自定义的几何体。该函数和OnPostRender相似,除了一点:不论脚本挂在相机上与否,OnRenderObject都会在任何GameO上被调用。
- OnPostRender:在相机完成场景的渲染后被调用。与OnRenderObject不同,仅当脚本挂在相机上并且是enabled时,该函数才会被调用。假如想要在所有相机和GUI渲染之后做操作,使用WaitForEndOfFrame协程。
- OnRenderImage(Pro only):在场景渲染完成后被调用,用于对屏幕的图像进行后处理,该消息被发送到挂到相机上的所有脚本。该函数允许利用基于shader的过滤器对最终图像进行处理,传入源渲染纹理,终止于目标渲染纹理;当相机有多个图像过滤器时,图像顺序被处理,前一个过滤器的目标渲染纹理作为下一个过滤器的源渲染纹理。
- OnGUI:为响应GUI事件,该函数每帧被调用多次,每个事件就调用一次;执行时先响应布局和重绘事件,随后是为每一次的输入事件执行布局和键盘/鼠标事件。
- OnDrawGizmos:为了可视化的目的,从而在场景视图中绘制小图标。该函数使用相对于Scene视图的鼠标的位置,允许快速挑选场景中重要的GameObject,当然假如组件在inspector中collapsed,则该函数就不会被调用。
协程Coroutines:
正常情况下协程是在Update函数返回时执行。协程的功能是,延缓其执行(yield) ,直到给定的YieldInstruction完成。协程的不同用途:
- yield:协程在所有的Update函数在下一帧被调用后继续执行。
- yield WaitForSeconds:在一个指定的时间延迟后继续执行,在该帧所有的Update函数被调用之后,仅可用于协程中的yield语句。
- yield WaitForFIexedUpdate:在所有脚本上所有的FixedUpdate被调用之后继续执行,即可用于协程中的yield语句。
- yield WWW:在WWW加载完成之后继续执行。
- yield StartCoroutine:等待MyFunc协程先完成,用于链接协程。该函数总是会立即返回,然而可以yield结果,这样就就会等到协程完成执行然后返回。使用JavaScript不必使用该函数,因为编译器会为你做这个工作,若使用C# 就需使用该函数了。
对象被销毁时When the Object is Destroyed:
OnDestroy这个函数在所有帧更新之后被调用,在对象存在的最后一帧中(对象被销毁来响应Object.Destroy或关闭一个场景),该函数不可以是协程。
当退出时When Quitting:
对于场景中所有active对象都会调用下列函数:
- OnApplicationQuit:在应用退出之前所有的游戏对象都会调用该函数。在编辑器中当用户停止播放时它将被调用;在webplayer中,当网页关闭时被调用。
- OnDisable:当行为不可用或非激活时,该函数被调用。当对象被销毁时,或对于任何清理工作的代码,该函数同样可被调用。当编译完成之后重新加载脚本,该函数可被调用,紧随其后脚本加载完成时调用OnEnable。
脚本生命周期流程图:
综上所述,关于脚本整个生命周期可参见unity3d脚本生命周期流程图。