Unity中常见的脚本生命周期函数及顺序

游戏物体生命周期

  • 场景中的游戏物体通过脚本来控制其具体行为。
  • 生命周期流程图点击跳转
  • 脚本里重点事件函数:
    • Awake:游戏物体实例化后并处于激活状态时调用,即使脚本组件没有激活也会调用,而且总是在Start()函数之前调用,用于初始化对象的引用和状态。
    • OnEnable:游戏物体与脚本组件激活时调用(会反复触发),用于进行初始化操作。
    • Start:游戏物体与脚本组件处于激活状态,在 Awake 之后调用,在Update()运行前调用(只调用一次,当物体关闭激活状态,再打开时不会反复触发),用于在对象被启用前进行初始化操作。
    • FixedUpdate:根据设定的帧率运行(帧率固定,主要用于刚体运算,存在平衡机制去约束),固定的时间间隔(一般为0.02秒)调用一次,用于执行物理计算相关的逻辑。
    • Update:每帧调用一次(帧率不固定,与硬件性能以及逻辑复杂度相关),用于更新对象的状态和执行逻辑操作。
    • LateUpdate:每帧调用一次,在Update()之后调用,用于在 Update 逻辑执行完成后进行一些额外的操作。
    • OnDisable:游戏物体/脚本组件关闭激活时调用(会反复触发),用于清理对象状态和资源
    • OnDestroy:当游戏物体销毁时调用,用于清理对象状态和资源。

  • 注意:在一个场景加载以后,场景当中的每个物体都会遵循上述原则去运行物体上挂载脚本的函数

核心要素

  • OnEnable/OnDisable可以反复触发
  • Awake/Start始终只触发一次
  • FixedUpdate运行帧率由:Edit-Project Settings-Time-Fixed Timestep的值决定 注:每秒运行帧率相等不代表运行时间相等。可通过Time.realtimeSinceStartup测试出来每次FixedUpdate()调用时间间隔是不一样的。
  • 为保证FixedUpate的固定帧率,通过设置Edit-Project Settings-Time Maximum Allowed Timestep来实现平衡机制,限定每次FixedUpdate()运行的最长时间。实现效果与性能的平衡。

帧循环/主线程概念

  • 为了保证数据安全,Unity核心的游戏逻辑全部都是在一个线程里完成。也就是我们常说的Unity主线程。 在主线程上运行一次完整的游戏逻辑帧我们称之为完成了一次帧循环,也称为主循环。
  • 注意几点:
    • 一个逻辑帧我们通常是指一次包含了以Update()为主的循环调用过程。因为我们游戏的逻辑大部分都是运行在Update()里面。
    • 一个逻辑帧里面可能包含了多次FixedUpdate()的调用。
    • Unity中是可以使用多线程的,但需要注意在Unity里一些关键性的数据在其它线程是不能访问修改的。
    private void Start() {
        ThreadStart threadStart = new ThreadStart(ThreadMain);
        Thread thread = new Thread(threadStart);
        thread.Start();
        Debug.Log("UnityMain线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
    }

    void ThreadMain() {
        Debug.Log("New线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString());
        //运行会报错:get_transform can only be called from the main thread.
        Debug.Log(transform.gameObject.name);
    }

  • Unity限制使用多线程的原因:
    • 保证数据安全
    • 降低编程难度
  • 为何还能保持高效率的运行?
    • Unity在底层实现了线程池,引擎底层来实现一些可使用多线程处理的任务
### Unity 生命周期函数调用顺序Unity 中,生命周期函数的执行顺序是固定且有序的。对于每个对象上的每个脚本实例而言,这些函数会依照特定序列被逐一触发。 #### 初始化阶段 - **Awake** 当场景加载完成之后,在任何 `Start` 方法前调用该方法。如果多个组件都定义了 `Awake()` 函数,则其实际调用次序不确定,不过开发者可以手动调整以确保预期行为[^2]。 - **OnBeforeTransformParentChanged (仅限于父物体变换即将改变时)** 此回调会在当前 GameObject 的 Transform 即将成为另一个 GameObject 子节点之前立即得到通知。 - **OnInitAnimator (仅适用于带有 Animator 组件的对象)** 这是在初始化动画控制器时会被调用的方法。 - **Start** 只有当 Script 实例第一次启用并准备开始工作的时候才会被执行一次;它通常位于第一个 Update 前面发生。 #### 更新循环 - **FixedUpdate** 物理计算和物理引擎相关的操作应该放置在此处,因为它是基于固定的时间间隔来进行更新而不是每一帧都刷新。 - **PreLateUpdate 和其他内部更新过程** 包含一系列由 Unity 自身管理的过程,比如摄像机渲染等。 - **Update** 是最常用的每帧更新逻辑所在位置,适合用来处理大多数的游戏逻辑业务,如输入检测、角色移动控制等等[^5]。 - **LateUpdate** 总是在常规 `Update` 循环结束后才运行,常用于跟随相机或者其他依赖于上一帧结果的操作。 #### 渲染相关 - **OnPostRender** 对应着每一个 Camera 执行完毕后的时刻,可用于自定义后期效果绘制等内容。 - **OnGUI/OnGUIScene(已废弃)** #### 销毁清理 - **OnDestroy** 在 MonoBehaviour 被销毁时调用,无论是通过代码还是由于场景切换等原因造成的卸载都会触发展开相应的资源释放动作。 #### 应用程序级别事件响应 - **OnApplicationPause(bool pauseStatus)** 表明应用程序进入暂停状态或是恢复活动状态之时所发生的事件。 - **OnApplicationFocus(bool focusStatus)** 用户界面获得或失去焦点的情况下将会激活此消息传递机制。 - **OnApplicationQuit()** 在应用正式结束前给予最后一次机会去执行必要的收尾任务,例如保存进度数据到持久化存储介质里[^4]。 ```csharp using UnityEngine; public class LifecycleExample : MonoBehaviour { void Awake(){ Debug.Log("Awake called"); } void OnEnable(){ Debug.Log("OnEnable called"); } void Start(){ Debug.Log("Start called"); } private void FixedUpdate(){ Debug.Log("FixedUpdate called"); } void Update(){ Debug.Log("Update called"); } void LateUpdate(){ Debug.Log("LateUpdate called"); } void OnDestroy(){ Debug.Log("OnDestroy called"); } void OnApplicationQuit(){ Debug.Log("OnApplicationQuit called"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

無限進步的全棧遊戲開發

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值