学习生命周期的时候发现官方出了两个版本的生命周期,旧版好像是5.0以前的,新版是5.0以后的,我自己翻译并整理了一下,画了两个图,希望对大家有帮助。
**注:**图是用Astah画的,想要原版的可以私信我。

旧版Unity生命周期

- 官方旧版生命周期

在这里插入图片描述

- 个人整理翻译版本

在这里插入图片描述

新版Unity生命周期

- 官方新版生命周期

在这里插入图片描述

- 个人整理翻译版本

在这里插入图片描述


生命周期函数

1、初始化阶段

Awake(唤醒)

当一个脚本实例被载入且 Active 为 true 时 Awake 会被调用,一个非激活状态的预制件 Instantiate 的时候不会调用 Awake ,在首次调用 SetActive(true) 时会且只会调用一次,也就是说同一个 GameObject 的 Awake 函数只会被调用一次。由于其调用顺序早于 Start,所以 Awake 常用于在游戏开始之前初始化变量或游戏状态,可以判断当满足条件后执行此脚本(只调用一次)。
注意:如果是在 Update 中调用的 SetActive(true) ,Awake 函数会立即被调用,而 Start 函数是在下一帧才调用的。
在这里插入图片描述

OnEnable(当可用)

当对象变为可用或激活状态时此函数被调用。(可多次调用)。

Reset(重置)(Editor)

Reset是在用户点击检视面板的Reset按钮或者首次添加该组件时被调用。此函数只在编辑模式下被调用。Reset最常用于在检视面板中给定一个最常用的默认值。

Start(开始)

物体载入且脚本对象启用时被调用1次,常用于数据或逻辑对象初始化(只调用一次)。
Start仅在Update函数第一次被调用前调用,且只会在脚本实例启用时被调用一次。
Awake总是在Start之前执行。可以按需调整延迟初始化代码。

2、物理阶段

FixedUpdate(固定更新)

FixedUpdate基于一个可靠的定时器被调用,独立于帧率之外。如果固定的时间步长小于实际的帧更新时间,那么每帧的物理循环可能会发生不止一次。处理物体的物理属性(Rigidbody、Force、Collider)或者输入事件时,需要用FixedUpdate代替Update,以使物体的物理表现更平滑。实际上,FixedUpdate并不是真的按照现实时间间隔执行的,而是按照Timer时间间隔执行的,但Timer并不是真正意义上的现实时间,它的作用是在运行环境下创造一个与现实时间高度相近的变量来实现物理帧的逻辑稳定。因为FixedUpdate的这个特质,强烈建议在此环节只做物理相关的处理,不要把其他类型(如网络帧同步)的处理也放入此步骤。默认频率大概为0.02s,该频率可手动修改。

在这期间的操作

固定更新结束后,系统内部会进行一系列的操作,最重要的莫过于Unity的内部物理更新,这个是真正的物理更新操作执行。
具体执行步骤大概如下:
在这里插入图片描述

OnTriggerXXX(触发)

触发器被触发时调用。

OnCollisionXXX(碰撞)

产生碰撞事件时调用。

yield WaitForFixedUpdate(协程:物理帧结束)

当物理帧执行完毕后会跳转到此协程,协程的调用跟方法是不同的,可以理解为在一段代码中设置一个卡点,当程序执行到这个卡点所匹配的时机时卡点后面的代码才会继续执行。

public class Test : MonoBehaviour
{
    void Awake()
    {
        Debug.Log("0");
        StartCoroutine(TestCoroutine());
        Debug.Log("2");
    }

    void FixedUpdate()
    {
        Debug.Log("3 - FixedUpdate");
    }

    IEnumerator TestCoroutine()
    {
        Debug.Log("1");
        yield return new WaitForFixedUpdate();
        Debug.Log("4");                      // 当物理帧结束(触发WaitForFixedUpdate)后才会执行这条语句。 
    }
}

物理阶段总结

该阶段的发生与渲染无关,其特性决定了其处理物理事件的功能,使物理展示效果更为平滑,另外固定更新的频率并非真的是固定的,实际的执行会根据CPU轮转时间片产生偏移,但这个偏移基本可以忽略不记。

3、输入事件阶段

鼠标、键盘、触屏、手柄等各类输入事件会在这个阶段触发,这个时间点物理更新已经执行(如果需要物理更新的话),而逻辑更新和渲染并未执行,要了解这个触发的时机,才能更好的掌握代码逻辑。

4、游戏逻辑阶段

Update(更新)

Update是真正的每帧调用的,由于系统性能以及游戏体量的区别,每一帧的刷新频率也是不同的,所以不要过分期待在Update方法中按时完成任务。
Update与FixedUpdate实际上是使用同一个线程的,update在loop中的处理方式是本次更新完毕再根据上一帧到现在的偏移时间判断是否进行下一次更新,Update的本质就是回调函数。只要是回调函数就存在上下文传递的损耗,所以如果想减少回调,可以考虑自己实现一套update机制,使用虚函数来代替update。具体内容可以了解另一篇文章:【Unity】Unity开发进阶(二)自定义Update

判断多个协程点

在yield WaitForFixedUpdate章节已经讲过协程的执行顺序,当Update执行过后,将会到达以下几个协程的触发点,如果在此之前设置了相关的协程,这时就会生效。

  • yield null
  • yield WaitForSeconds
  • yield WWW:这个比较重要,当网络任务执行完成后,会在当前帧的这个时间点执行WWW之后的操作。一般用于异步加载资源。
  • yield StartCoroutine

内部动画更新

在几个协程过后,Unity将进行第二次大规模的系统内部操作,主要的工作内容就是动画的更新,具体内容如下:
在这里插入图片描述

LateUpdate(延后更新)

每帧Update方法调用之后会调用本方法。因为游戏开发过程中经常会有一个二次计算的情况,比如主角移动,相机跟着移动。如果相机也在主角移动时跟随,当有物体跟玩家之间产生了相位,就可能会出现抽搐抖动等情况(因为并没有在这一帧逻辑完全结束后调用跟随)。所以LateUpdate的出现能够使程序更加顺畅。

5、渲染阶段

OnWillRenderObject

当即将渲染物体时调用。

OnPreCull

这个函数仅用于宿主为摄像机的脚本。当此摄像机剔除了某个渲染场景时候触发此消息。

OnBecameVisable(即将可见)

当物体即将可见时调用。

OnBecameInvisible(即将不可见)

当物体即将不可见时调用。

OnPreRender(即将渲染)

这个函数仅用于宿主为摄像机的脚本。当此摄像机开始渲染某个场景时候触发此消息。
在所有渲染开始之前调用,这个方法其实是很考究的,我看到大部分网友对于这个方法都是抄了几种用法:加入脚本、设定标题、设定按钮客户端事件、设定控件的状态、加入脚本块。
个人觉得渲染前可以做的事并不仅仅如此,比如是不是可以考虑在渲染前做一些渲染优化,虽然现在已经有很多插件了,但是如果程序设计的好可以考虑自己实现一套优化,这样更贴合自己的程序。

OnRenderObject

这个函数仅用于宿主为摄像机的脚本。当使用Graphics.DrawMeshNow 或者其他函数绘制自己建立的物体渲染完毕时触发。

OnPostRender

这个函数仅用于宿主为摄像机的脚本。当此摄像机范围内所有渲染都完成时候触发此消息。

OnRenderImage

当所有渲染完成image的postprocessing effects(只有pro版支持)后触发。

OnDrawGizmos(Gizmos渲染)

Gizmos一般是为开发者使用的,指的是开发时场景编辑器中所展示的那些相机、线框之类的物体。所以此方法里的内容一般不会需要发布到生产环境中。

GUI渲染

用户界面渲染的工作会在这一步执行。

yield WaitForEndOfFrame(协程:帧结束)

当前帧彻底结束后会执行此协程。协程运行情况如下:

public class Test : MonoBehaviour
{
    void Awake()
    {
        Debug.Log("0");
        StartCoroutine(TestCoroutine());
        Debug.Log("2");
    }

    void Update()
    {
        Debug.Log("3 - Update");
    }

    void LateUpdate()
    {
        Debug.Log("4 - LateUpdate");
    }

    IEnumerator TestCoroutine()
    {
        Debug.Log("1");
        yield return new WaitForEndOfFrame();
        Debug.Log("5");                      // 当帧结束(触发WaitForEndOfFrame)后才会执行这条语句。 
    }
}

6、暂停阶段

OnApplicationPause(应用暂停)

应用暂停时会调用此方法,取消暂停后会从FixedUpdate开始重新执行。

7、退出阶段

OnDestroy(销毁)

当物体被销毁时调用,一般用于清理内存。

OnApplicationQuit(应用退出)

当应用退出时调用,但有时会失效,此方法为不稳定的方法,正常情况下可以用于保存退出前的信息,但最好使用更稳妥的方式,因为此方法有时不会被调用,比如Android环境。


更多内容请查看总目录【Unity】Unity学习笔记目录整理

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐