« effekseer 的 shader 转译 | 返回首页 | 全民大规模新冠检测方案的一些想法 »

层次组件的问题

最近思考了 ECS 框架中的一些问题。

具体业务中,有许多组件的构成非常复杂,本质上数据是有层次结构的。用一个二维表的结构很难清晰表述。它还牵扯到另一个问题:是否需要支持一个实体有多个统一类型的组件。例如,玩家实体身上多个装备栏、多个技能 Buf 该如何表达?

我有一些不成熟的想法,还没有具体落地,先记录一下:

在目前的 ECS 框架中,我以内存数据库的形式管理所有的数据。把 Entity/Component (实体、组件)看成是一张二维稀疏表。每个 Entity 占一行,每类 Component 占一列。整张表为一个 world 。

而我最近的反思是,一个世界不应该只有一张表,没有理由把所有数据都塞入同一张二维表。

以物品栏 Inventory 为例,每个角色都会有一个 Inventory ,Inventory 是由诸多物品格 slot 构成的。这就是一个有层级关系的数据结构:角色 -> 物品栏 -> 物品格。

如果我们去掉物品栏这一层抽象,那么,角色这个 Entity 上就需要有复数个物品格 Component 。

通常,如果我们有一个系统 system 是用来处理身上携带物品对角色起的效应,那么最好在 select 物品时,可以把同一个角色身上的所有物品聚合在一起处理。它们之间是有关联的。

相比把这些数据塞入一张大表,一个可能更好的模式或许是为所有的物品格单独建一张表。在这张表中,Entity 指的是单个物品格,同一物品格可以有多个 Component 和 Tag 。有一个 Component 保存的是它的 id ,用来和存放角色 Entity 的那张表发生关联。

在角色 Entity 的表中,我们只维护它身上有几个有效的物品格,真正的数据都放在物品栏的专用表中。

在物品栏的专用表中,为每个物品格生成一个唯一 id ,这个 id 是由角色 id 以及物品格在该角色的 Inventory 中的编号构成的。

使用 ECS 的 select 已经实现的 order 模式(一种特殊的 select 方式,可以根据特定组件 id 排序,以特定的次序而不是构建持续遍历),我们可以做到把同一个角色身上的所有物品格聚在一起遍历。

同时,还可以给物品格打上 tag ,select 时可以挑选出关注的那一部分:例如可以按物品用途分类等。


支持多张表并不需要修改已经写好的 luaecs 的实现,只是原有的名字起的不恰当。单张表不应称为 world ,而需要再加一层 world 来管理多张表。

把数据拆分成多张表后,底层也可以对 order tag 做进一步的优化。因为原有的 order 模式虽然可以让 select 以特定次序遍历 entity ,但相比普通的按构造次序顺序遍历 entity ,查询 entity 的 component 的时间复杂度有可能从 O(1) 下降到 O(log N) 。

我们可以增加一个方法让使用者主动定期按 order tag 整理一张表的内部内存实际布局,提高顺序访问的效率。整个整理工作代价比较大,但分拆数据到多张表可以减少很多整理成本。

Comments

背包没必要用ecs~

@403city
nosql不是万能的,建立索引和key-value表需要漫长的时间,大型数据库软件,可以支持大型的各种查询的结果集返回,nosql是做不到的,还有就是结果集可以在客户端进行二次处理,同样的内存和CPU,客户端处理结果集比处理value在很多时候速度要快的多,因为结果集也是一个大型的表格,value在很多时候仅仅是一个文件。

非游戏人,为什么不用nosql存储

是不是有点过度设计了,如果是我的话,大概率 物品栏 这一层就停了,组件模式从我的思考角度就是对一个主体的某些功能实现热插拔。
物品栏的所有功能是处理数据的内部业务逻辑,完全没必要再往下要组件化,物品栏 = data+view,然后view显示和功能由data驱动。

脑瓜子已经变成数据库的形状了~

Post a comment

非这个主题相关的留言请到:留言本