文章目录
Unity DOTS 与 MonoBehaviour 生命周期执行顺序
1. 概述
在 Unity 引擎中,DOTS(特别是 ECS 架构)的 System 与传统的 MonoBehaviour 并非在多线程中随机交错执行。相反,它们统一运行在主线程的玩家循环中,按照引擎预设的阶段性顺序依次执行。
理解这一执行顺序对于架构设计至关重要,它直接决定了数据读写的时序正确性与逻辑归属。如果盲目地在 MonoBehaviour 与 DOTS 系统间进行数据交互而不清楚执行先后,极易导致数据读写错位、一帧延迟或状态竞争等问题。
2. 默认玩家循环结构与 DOTS 系统组插入点
Unity 默认的玩家循环主要包含以下几个按时间先后排列的阶段:Initialization → EarlyUpdate → FixedUpdate → Update → PreLateUpdate → PostLateUpdate。
在默认的 DefaultWorld 初始化时,DOTS 的三大顶层系统组会被自动注入到上述阶段的特定位置:
- InitializationSystemGroup:挂在
Initialization阶段末尾。 - SimulationSystemGroup:挂在
Update阶段末尾。 - PresentationSystemGroup:挂在
PreLateUpdate阶段末尾。
3. 一帧内的完整执行顺序
以下基于默认的 DefaultWorld 且未修改 Player Loop 的情况,按时间从先到后详细列出一帧内的执行顺序:
| 执行阶段 | 具体执行内容说明 |
|---|---|
| Initialization 阶段 | 引擎初始化操作。阶段末尾执行 InitializationSystemGroup。 |
| EarlyUpdate 阶段 | 引擎内部更新(如输入系统状态轮询等),通常不包含开发者直接编写的逻辑。 |
| FixedUpdate 阶段 | 执行 MonoBehaviour.FixedUpdate。若启用了 FixedStepSimulationSystemGroup,其关联的物理相关 DOTS 系统也会在此阶段更新。 |
| Update 阶段 | 执行 MonoBehaviour.Update,以及引擎内部动画系统等更新。 |
| Update 末尾 | 执行 SimulationSystemGroup,包含核心游戏逻辑的 DOTS 系统。 |
| PreLateUpdate 阶段 | 执行 MonoBehaviour.LateUpdate,以及粒子系统、UI 布局更新等。 |
| PreLateUpdate 末尾 | 执行 PresentationSystemGroup,通常用于渲染前的数据和状态准备。 |
| PostLateUpdate 阶段 | 渲染前收尾工作(如等待渲染线程完成、计算帧时间等)。 |
4. 执行顺序图示
以下为各阶段与 DOTS 组对应关系的简易文本示意图,直观展示一帧的执行流:
Initialization ──> [InitializationSystemGroup]
EarlyUpdate ──> (引擎内部更新)
FixedUpdate ──> MonoBehaviour.FixedUpdate / [FixedStepSimulationSystemGroup]
Update ──> MonoBehaviour.Update (及动画等)
└──> [SimulationSystemGroup]
PreLateUpdate ──> MonoBehaviour.LateUpdate (及粒子、UI)
└──> [PresentationSystemGroup]
PostLateUpdate ──> (渲染前收尾)
5. 数据可见性与读写依赖
在同一帧内,由于 DOTS 系统组和 MonoBehaviour 回调是顺序执行的,因此数据的读写可见性遵循严格的先后关系:
- InitializationSystemGroup 生成的数据:在同帧的所有 MonoBehaviour.Update / LateUpdate 以及后续的 DOTS 系统组中均可见。
- MonoBehaviour.Update 中对组件的修改:由于
Update阶段早于Update末尾的SimulationSystemGroup,因此这些修改会被后续的 SimulationSystemGroup 立即看到。 - SimulationSystemGroup 的修改:由于
Update阶段早于PreLateUpdate,这些修改可在同帧的 MonoBehaviour.LateUpdate 中读取。 - MonoBehaviour.LateUpdate 的修改:由于
LateUpdate早于PreLateUpdate末尾的PresentationSystemGroup,这些修改可被 PresentationSystemGroup 捕获(常用于渲染前的最终 Transform 或外观数据同步)。
特别注明:即便 DOTS 系统内部使用了 C# Job System 进行多线程并行计算,系统的
OnUpdate方法在执行完毕前会通过依赖关系(state.Dependency)或显式Complete()等待其调度的所有 Job 完成。因此,在宏观的玩家循环层面上,逻辑上仍是顺序执行的,上述跨框架的数据可见性规则不受影响。
6. 自定义执行顺序的可能性
如果默认的执行顺序无法满足项目架构需求,开发者完全可以通过 API 进行自定义:
- 修改挂载点:通过
PlayerLoop.GetCurrentPlayerLoop()获取当前玩家循环实例,并利用ScriptBehaviourUpdateOrder.AppendWorldToPlayerLoop将自定义的 World 注入到指定的 PlayerLoop 阶段中。 - 手动驱动:也可以完全脱离 Player Loop 机制(例如取消默认 World 的自动更新),在自定义的 MonoBehaviour 或其他生命周期中手动调用
world.Update()来接管 DOTS 系统的更新时机。
7. 常见误区澄清
-
误区:InitializationSystemGroup 仅在启动时执行一次。
澄清:与 MonoBehaviour 的Awake/Start不同,InitializationSystemGroup挂载在 Player Loop 的Initialization阶段末尾,每一帧都会被执行,常用于处理每帧的初始化逻辑、输入状态重置或场景流式加载。 -
误区:DOTS 系统与 MonoBehaviour 是多线程交叉执行的。
澄清:DOTS 的顶层系统组更新与 MonoBehaviour 的回调在主线程上是顺序分阶段运行的。虽然 DOTS 内部的 Job 会利用多核 CPU 并行处理数据,但系统组与系统组之间、系统组与 MonoBehaviour 回调之间不会发生多线程交叉执行。
8. 总结
在默认配置下,DOTS 系统与 MonoBehaviour 生命周期的核心执行顺序可浓缩为:
InitializationSystemGroup → FixedUpdate → Update → SimulationSystemGroup → LateUpdate → PresentationSystemGroup
掌握这一时序对于架构决策(如将逻辑前移还是后移)和数据同步(避免读写时序错位)至关重要。只有严格遵循此顺序进行跨框架通信,才能确保游戏逻辑的确定性与无延迟表现。
更多内容请查看总目录【Unity】Unity学习笔记目录整理
3万+

被折叠的 条评论
为什么被折叠?



