引擎组装——引擎有哪些子系统,怎么组装

一句话

引擎本身是一个多子系统协作的系统,组装方式类似通信程序的网络系统:每个子系统有独立的生命周期和运行方式,由引擎统一调度;引擎负责「怎么运行」,不知道游戏规则。


一、引擎可能包含的子系统

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 在运行时注册、调度、执行