Unity中常用的生命周期函数


下图为Unity脚本生命周期流程图,图源:Unity官方手册
monobehaviour_flowchart.png

由图可知,Unity生命周期包含几个主要阶段:初始化阶段(Initialization),物理与输入阶段(Physics+Input Events),游戏逻辑更新(Game Logic),渲染与界面(Scene Rendering+Gizmo Rendering+GUI Rendering),结束与清理(Decommissioning)。

初始化阶段

1.Awake()

触发时机:

当 GameObject 激活且脚本实例化时立即调用,无论脚本自身是否启用。Awake()在脚本生命周期中只会被调用一次。

用途:

初始化与脚本状态无关的变量或引用(如 GetComponent),但依赖 GameObject 的激活状态。

2.OnEnable()

触发时机:

当 GameObject 处于激活状态(activeInHierarchy == true)且脚本组件被启用(enabled == true)时触发,包括以下场景:

  • GameObject 从非激活变为激活状态(SetActive(true))。

  • 脚本组件从禁用变为启用状态(enabled = true)。

每当条件满足时调用一次OnEnable(),即OnEnable可能被多次调用。

用途:
  • 注册事件或回调(确保对象激活时能接收通知)。

  • 启动或重启协程(需手动调用 StartCoroutine())。

  • 重置临时状态或数据。

3.Start()

触发时机:
  • 当 GameObject 激活且脚本启用时,在首次 Update() 前调用,仅执行一次。

  • 所有 Awake() 方法(包括其他对象)已执行完毕,但不同脚本的 Start() 执行顺序未定义。

用途:
  • 初始化依赖其他对象或组件的逻辑(需确保依赖对象的初始化在 Awake() 中完成)。

  • 执行单次设置(如游戏初始状态配置)。

物理与输入阶段

1.FixedUpdate()

触发时机:
  • 按固定时间间隔(默认 0.02 秒)触发,与帧率无关。该值可在 Unity 的 Project Settings → Time → Fixed Timestep 中调整。

  • 可能在一帧内多次调用以同步物理时间(如帧率过低时)。

  • 触发顺序通常早于 Update(),但具体取决于物理计算需求。

用途:
  • 处理所有与物理引擎相关的操作(如 Rigidbody 控制、力的施加)。

  • 执行需要严格按固定时间步长更新的逻辑(如回合制计时)。

注意事项:

  • 避免耗时操作,确保物理模拟流畅性。

  • 物理属性修改(如速度、力)应在此完成,而非 Update()。

  • 输入检测需在 Update() 中处理,再传递至 FixedUpdate()。

2.物理事件(如OnCollisionEnter(), OnTriggerEnter())

触发时机:

在物理引擎完成每步计算后触发,紧随 FixedUpdate() 之后,可能在一帧内多次触发(若多次调用 FixedUpdate())。

具体顺序:FixedUpdate() → 物理引擎更新 → OnCollision/TriggerXXX() → Update()

用途:
  • OnCollisionEnter():响应物理碰撞(如伤害计算、音效播放),需双方 Collider 未标记为 Trigger。

  • OnTriggerEnter():检测物体进入触发区域(如收集品、陷阱),需至少一方 Collider 标记为 Trigger。

  • OnCollisionStay()/OnTriggerStay():持续碰撞/触发时每帧调用。

  • OnCollisionExit()/OnTriggerExit():碰撞/触发结束时调用。

注意事项:

  • 确保至少一个物体带有 Rigidbody(触发器可接受运动学 Rigidbody)。

  • 避免在物理事件中执行耗时操作,必要时使用缓存或协程。

  • 通过碰撞矩阵优化检测,减少不必要的交互。

3.输入事件(如OnMouseXXX())

触发时机:

以OnMouseDown()为例,Unity 通过射线检测判断鼠标点击是否落在目标 Collider 上,若满足条件,OnMouseDown()在鼠标按下(Button Down)的同一帧触发。

用途:
  • 点击选择物体(如拾取道具、选中角色)。

  • 触发点击动画或音效(如按钮反馈)。

游戏逻辑更新

1.Update()

触发时机:
  • 每帧调用一次:Update() 的调用频率与游戏帧率(FPS)直接相关。例如,若帧率为 60 FPS,则每秒调用 60 次。

  • 帧率依赖性:由于调用间隔不固定(由 Time.deltaTime 表示),需通过时间增量来平滑逻辑(如移动速度),避免帧率波动导致行为不一致。

用途:

非物理游戏逻辑,例如:

  • 输入检测:轮询键盘、鼠标或触摸输入(如 Input.GetKeyDown)。

  • 动画控制:更新角色动画状态或 UI 动画。

  • 状态管理:处理游戏逻辑的实时状态切换(如技能冷却、AI 决策)。

  • Transform 操作:直接修改物体的位置、旋转或缩放(如非物理驱动的移动)。

避免高开销操作:

  • 减少在 Update() 中执行复杂计算(如物理射线检测、资源加载)。

  • 使用标志位或缓存机制优化高频逻辑(如利用标志位设置每5帧执行一次)。

2.LateUpdate()

触发时机:
  • 严格顺序:LateUpdate() 在 同一帧内所有 Update() 方法执行完毕后调用,包括其他脚本的 Update()。

  • 帧率依赖:与 Update() 相同,调用频率取决于游戏帧率(FPS),每帧调用一次。

用途:
  • 摄像机跟随:确保摄像机更新发生在玩家/目标物体的位置计算之后,避免画面抖动。

  • 依赖其他对象最终状态的逻辑:

    • UI 元素对齐:在物体位置更新后调整 UI 的屏幕坐标(如血条跟随角色)。

    • 物理模拟后的处理:如记录物体移动轨迹(需基于最终位置)。

  • 渲染前的最后调整,材质或光照更新:根据场景状态动态修改渲染参数(如雾效强度)。

  • 跨脚本顺序控制,确保数据同步:若 Script A 的 Update() 修改数据,Script B 的 LateUpdate() 可安全使用该数据。

渲染与界面

1.渲染事件(OnBecameVisible(),OnBecameInvisible(),OnRenderObject()等)

触发时机:
  • 与摄像机渲染流程强相关:

    • 所有事件均围绕摄像机的渲染管线阶段触发,例如:

      渲染前:OnPreRender()、OnWillRenderObject()

      渲染中:OnRenderObject()

      渲染后:OnPostRender()、OnRenderImage()

      可见性变化:OnBecameVisible()、OnBecameInvisible()

    • 事件触发顺序严格遵循Unity的渲染生命周期逻辑。

  • 依赖对象的渲染状态:

    OnBecameVisible()/OnBecameInvisible() 依赖对象的Renderer组件激活性改变。

    OnWillRenderObject()仅在对象被摄像机实际渲染前触发。

    OnPreRender()、OnPostRender()、OnRenderImage()需绑定到摄像机对象。

  • 帧率依赖性:

    所有事件均在每帧的渲染阶段触发。

用途:
  • 性能优化:

    OnBecameVisible()/OnBecameInvisible():动态管理不可见对象的资源(如禁用粒子效果)。

    OnPreRender()/OnPostRender():控制摄像机渲染目标,减少冗余计算。

  • 自定义渲染逻辑:

    OnRenderObject():手动绘制几何体(如调试线框)。

    OnRenderImage():实现后处理效果(如模糊、调色)。

    OnWillRenderObject():逐摄像机修改材质属性(如动态 LOD)。

  • 资源管理:

    按需加载/卸载资源(如OnBecameVisible()加载高清纹理)。

    清理临时渲染资源(如OnPostRender()释放 RenderTexture)。

    2.OnDrawGizmos()

OnDrawGizmos()是个特殊的生命周期函数,仅在编辑器模式下生效。

触发时机:
  • 当场景视图发生以下操作时,OnDrawGizmos() 会被调用:

    1. 摄像机移动、旋转或缩放。

    2. 对象被选中或取消选中。

    3. 场景视图的任意更新(如脚本修改对象属性)。

  • 在编辑器模式下,无论是否运行游戏,均会触发。

  • 在发布后的游戏中,Gizmos 不会渲染。

用途:
  • 调试与可视化,如绘制辅助线(标记路径、范围或方向)、显示碰撞体(可视化碰撞体形状,无需运行即可观察)、标记关键点(如生成点、触发器位置、AI 路径点等)。

  • 开发工具扩展,自定义编辑器工具,为插件或工具绘制可视化界面(如地形编辑器的笔刷范围)

  • 快速验证逻辑,在编辑模式下直接观察算法结果(如网格生成、寻路节点)。

注意事项:

避免在 OnDrawGizmos() 中执行复杂计算或高频绘制大量图形,否则会降低编辑器流畅度。

3.OnGUI()

触发时机:

OnGUI() 的触发与 Unity 的事件处理循环(Event Processing) 紧密相关,而非简单的“每帧多次”。具体规则如下:

  • 每帧至少调用一次:用于处理基本的 GUI 渲染和事件响应。

  • 事件触发额外调用:当有输入事件(如鼠标点击、键盘按下)发生时,Unity 会多次调用 OnGUI() 以处理事件传播。

用途:
  • 调试工具:在开发过程中,OnGUI()可以快速创建按钮、标签等 UI 元素,方便调试和测试游戏逻辑,也可用于显示变量、状态等实时信息,帮助开发者监控游戏运行情况。

  • 原型设计简单UI:在项目初期,OnGUI 可以快速搭建简单的 UI 原型。

  • 编辑器工具:用于创建自定义编辑器窗口或 Inspector 扩展,方便资源管理和配置。

注意事项:

OnGUI 每帧调用,频繁使用可能影响性能,不适合复杂 UI。现在更推荐使用UGUI或UI Toolkit替代进行UI开发。

结束与清理

1.OnDisable()

触发时机:
  • gameobject被禁用,即调用gameObject.SetActive(false)时,该对象以及其子对象所有脚本的OnDisable()会被触发。

  • 脚本被禁用时,该脚本的OnDisable()会被调用。

  • 对象被销毁或场景卸载时未被标记为DontDestroyOnLoad,在OnDestroy()前触发OnDisable()

用途:

清理资源和终止逻辑,包括取消事件订阅、停止协程与定时器、释放临时资源,以及重置状态以确保下次启用时处于初始状态。

2.OnDestroy()

触发时机:
  • 调用 Destroy(gameObject) 或 Destroy(this) 时,触发对应对象的 OnDestroy()。

  • 当场景切换且对象未标记为 DontDestroyOnLoad 时,场景中的对象会被销毁。

  • 应用退出时,所有活动对象的 OnDestroy() 会被触发(但非强制终止的情况,如崩溃时可能不会调用)。

  • 通过 Destroy(component) 移除脚本组件时,该组件的 OnDestroy() 会被调用,但 GameObject 仍存在。

用途:

主要用于执行对象销毁前的清理操作,包括释放资源(内存释放等)、取消事件订阅、停止协程或Invoke定时任务,另外可用于保存数据,但应用非正常退出时可能无法触发。

3.OnApplicationQuit()

触发时机:

应用程序正常退出时调用,Unity编辑器模式下点击Play按钮中止播放时调用。注意在移动端切换到后台时不调用OnApplicationQuit(),而是调用OnApplicationPause(true)。当程序崩溃或强制中止(如在任务管理器关闭进程)不调用OnApplicationQuit()。

用途:

保存数据,终止协程、计时与线程,释放与清理资源,发送退出事件。


文章作者: 10n31y9047
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 10n31y9047 !
  目录