深入 ECS
前面九章学的工具——Query、Commands、Res、消息、observer——有一个共同点:你从不直接碰 World,而是隔着柜台跟它打交道。系统签名是一张申请单,写明要读哪几列、写哪几列,引擎按单配货;改动要么走命令队列等同步点,要么在引擎划定的窗口里进行。这套规矩换来的东西在第 4 章和第 6 章都见过:自动并行、帧内一致。
但有些活,柜台办不了:
- 存档:把世界里的每个实体、连同它身上的每个组件写下来——可“每个组件”是哪些组件,写申请单的时候根本不知道;
- 检查器:游戏跑着,随手点开任意一个实体看它的全部家当——同样没法预先声明;
- 工具与测试:写一段一次性的搭建代码、在测试里直接摆布世界,没有调度也没有系统,柜台连开都没开。
这些活需要的不是更大的申请单,而是一把能开一切的钥匙。本章就是来交钥匙的:
- 独占系统与 World API——拿到
&mut World,以及它上面那族“没有中间商”的方法; - 实体句柄——
EntityRef、EntityMut、EntityWorldMut,对单个实体的三档授权; - 档案室——Archetype 与 Table/SparseSet 两种存储:第 1 章承诺的“缓存友好的数据布局”、第 3 章承诺的“子表与遍历顺序”,旧账都在这里结清;
- 打包参数——
SystemState、#[derive(SystemParam)]、#[derive(QueryData)],把常用的形状起成名字; - 变更检测的发条——第 4 章那句“更多机关在第 11 章”指的全部机关;
- Disabled——让实体隐身而不销毁。
要说在前面的是:这些不是日常主力。写游戏逻辑,Query 加 Commands 仍然是九成场合的正确答案——它们能并行,钥匙不能。但剩下那一成(工具、存档、调试、读懂别人的高级代码)绕不开今天的内容;官方示例和生态插件的源码里,这些 API 随处可见。
本章的舞台还在灰岩镇。一年一度的大盘点到了:镇务官艾达要清点全镇每一户的人口与存粮,给档案室归册,再把总册贴上公告栏。挨家挨户、翻箱倒柜、当场记录——这份差事,恰好要用上本章的每一把钥匙。开工。