引擎组装——引擎有哪些子系统,怎么组装
一句话
引擎本身是一个多子系统协作的系统,组装方式类似通信程序的网络系统:每个子系统有独立的生命周期和运行方式,由引擎统一调度;引擎负责「怎么运行」,不知道游戏规则。
一、引擎可能包含的子系统
1 2 3 4 5 6 7 8 9 10 11 12
| 引擎可能包含的子系统: ├── 渲染系统 ← GPU 交互、Draw Call、渲染管线 ├── 物理系统 ← 碰撞检测、刚体模拟、约束求解 ├── 音频系统 ← 声音播放、3D 音效、混音 ├── 输入系统 ← 键盘/鼠标/手柄/触摸 ├── 资源系统 ← 加载、缓存、异步加载、引用计数 ├── 场景系统 ← 场景图、节点管理、摄像机 ├── 脚本系统 ← Lua/Python 绑定、脚本执行 ├── UI 系统 ← 控件树、事件处理、布局 ├── 动画系统 ← 骨骼动画、状态机、混合 ├── 粒子系统 ← 粒子发射、更新、渲染 └── 网络系统 ← 同步、预测、回滚(游戏专用)
|
ECS 只是引擎的数据组织子系统:
1 2 3 4 5 6
| ECS ├── World ├── Entity ├── Component Storage ├── Query └── System Scheduler
|
二、引擎 = 支撑子系统,Game = 业务子系统
1 2 3
| 游戏程序 ├── Engine(支撑子系统) ECS / Rendering / Physics / Input / Audio / Resource / Scene └── Game(业务子系统) Player / Enemy / Weapon / Character / Inventory / Quest / GameRule
|
Engine Component 和 Game Component 在「组件化」层面没有区别。 区别只是:Engine Component 支撑游戏,Game Component 实现具体游戏。
三、谁来组装:GameApplication
不是 main 一个个 new 所有东西,而是 GameApplication 负责组装:
1 2 3 4 5 6 7 8 9 10 11
| int main() { GameApplication app; app.run(); }
class GameApplication { void run() { Engine engine; Game game; game.registerComponents(engine); game.registerSystems(engine); engine.run(); } };
|
Engine 负责「怎么运行」
1 2 3 4 5 6 7 8 9 10 11
| class Engine { void run() { while (running) { input.update(); ecs.update(); physics.update(); rendering.render(); audio.update(); } } };
|
Engine 负责生命周期、运行循环、系统调度、基础设施、资源管理;它不知道游戏规则。
Game 负责「运行什么」
1 2 3 4 5 6 7 8 9 10 11
| class Game { void registerComponents(Engine& engine) { engine.ecs.registerComponent<Transform>(); engine.ecs.registerComponent<Health>(); engine.ecs.registerComponent<Weapon>(); } void registerSystems(Engine& engine) { engine.ecs.addSystem<MovementSystem>(); engine.ecs.addSystem<CombatSystem>(); } };
|
四、组装关系与运行时路径
1 2 3 4 5 6 7 8 9 10 11 12 13
| GameApplication │ ┌──────────────┴──────────────┐ ↓ ↓ Engine Game ┌─────┼─────┐ ┌────────┼────────┐ ↓ ↓ ↓ ↓ ↓ ↓ ECS Rendering Physics Character Combat Inventory │ └── Scheduler │ ↓ Game Systems(Movement / Combat / Enemy / Inventory)
|
真正运行时:
1
| GameApplication → Engine → Scheduler → Game Systems → ECS World → Game Components
|
五、不要把 Game System 和 Engine Scheduler 混为一谈
1 2
| CombatSystem → 业务(找到攻击者、计算伤害、修改 Health) Scheduler → 支撑(只知道什么时候运行 CombatSystem)
|
Scheduler 不知道「伤害是多少」,只知道「什么时候运行 CombatSystem」。
六、需要回答的问题
- 引擎子系统的启动顺序是什么?——谁先启动、谁后启动,依赖关系决定启动顺序(输入在物理前、物理在渲染前)
- 哪些子系统是框架化的(有自己的线程/循环),哪些是接口化的?——渲染/物理/音频通常框架化(有自己的循环/线程),数学工具、资源格式转换通常接口化
- 子系统之间怎么通信?——直接调用?消息队列?事件系统?(引擎里通常是事件系统/订阅发布)
- 引擎的异常处理流: 渲染崩溃怎么恢复?物理模拟超时怎么处理?
七、游戏类型驱动引擎成长
每一种游戏其实是在驱动不同的引擎模块成长。 先做最小引擎,再通过游戏需求推动系统增加:
1 2 3 4 5 6
| 阶段 1:方块运动测试 验证 GameLoop/ECS/Renderer/Input/Time 阶段 2:打砖块 增加碰撞/生成/删除/生命周期(ECS 基本模型成型) 阶段 3:马里奥横版闯关 增加世界/角色/物理/摄像机(开始像真正游戏) 阶段 4:塔防 增加 AI/大量实体/子弹(ECS 优势明显) 阶段 5:俯视角 RPG 增加战斗/背包/装备/对话/任务(接近商业游戏结构) 阶段 6:简单 3D 最后再进入(3D Renderer/摄像机/模型/光照)
|
与其他线的关系
- 与游戏系统组件线:引擎是支撑,游戏组件是业务——组件调用引擎能力,引擎不依赖游戏组件
- 与游戏系统组件组装线:引擎组装管「引擎内部怎么拼」,组件组装管「游戏组件怎么拼成游戏」
- 与从指令到系统主线:引擎组装 = 系统拆分原则在游戏领域的应用(业务系统 vs 网络系统 vs 引擎系统)
- 与网络系统线:引擎的子系统组装方式类似通信程序的网络系统——框架化心脏 + 被驱动的组件
- 与 ECS 与注册机制线(拆解与组织 04):ECS 的 System Scheduler 是注册机制的核心——System 在运行时注册、调度、执行