【Unity】Unity 生命周期

本文详细介绍了Unity游戏引擎中各个阶段的生命周期函数,包括初始化、物理、输入事件、游戏逻辑、渲染、暂停及退出阶段的关键函数。解析了每个函数的用途及调用时机,有助于开发者更好地理解和运用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


学习生命周期的时候发现官方出了两个版本的生命周期,旧版好像是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学习笔记目录整理

### Unity 中 MVC 架构的生命周期Unity 开发中,MVC(Model-View-Controller)是一种常见的设计模式,用于分离游戏逻辑、数据管理和用户界面展示的功能模块。这种架构有助于提高代码可维护性和扩展性。 #### Model 的角色与生命周期 Model 是负责管理应用程序的数据和业务逻辑的部分。它独立于 View 和 Controller 运作,并通过事件或其他机制通知它们状态的变化。通常情况下,在 Unity 中,Model 可能是一个脚本组件或一个单独的对象,用来存储和处理游戏中的核心数据[^1]。 当应用启动时,Model 被初始化并加载必要的初始数据;在其整个生命周期中,它会持续更新以反映当前的游戏状态直到被销毁为止。 #### View 的职责及其生命周期 View 主要关注如何向用户呈现信息以及接收用户的输入反馈。在 Unity 场景下,这可能涉及 UI 元素如按钮、滑动条或者 3D 对象等视觉表现形式。每当有来自控制器的动作触发或是模型内部发生了改变时,视图就需要重新渲染来显示最新的情况给玩家看。 一旦场景载入完成之后,所有的 Views 都会被实例化出来准备接受交互操作直至卸载该特定场景之前一直存在于此期间内保持活跃状态等待刷新指令执行相应动作。 #### Controller 的功能描述及运作流程 作为连接 Models 和 Views 的桥梁, Controllers 接收外部命令(比如鼠标点击),然后决定哪些方法应该调用去修改 models 或者更改 views 。在一个典型的 unity项目里 controller 往往表现为带有 OnClick() 方法响应函数绑定到 button 上等等控件上的单击事件处理器; 它们也可能订阅 model 发布的通知以便及时作出反应调整 view 显示内容匹配最新状况.[^2] 综上所述,Unity 中实现 MVC 设计模式可以有效帮助开发者构建清晰结构化的程序框架,使得各个部分之间相互协作更加顺畅高效的同时也便于后期维护升级工作开展顺利进行下去. ```csharp // Example of a simple Controller implementation in Unity public class ButtonController : MonoBehaviour { public void HandleButtonClick(){ Debug.Log("Button was clicked!"); // Update the model or notify other components as needed. } } ```
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值