ECS 的核心是通过为 实体 附加不同的 组件 来组合成不同的对象,而 EnTT 使用 稀疏集 来作为存储的实现
-
存储组件
作为组件池的存储时,entt::null在 稀疏数组 中用于表示某个 实体 不含有当前组件池存储的组件, 而当实体被移除组件时,entt::tombstone将在 密集数组 中找到原先组件所在的位置, 并占据该位置, 而不是默认的替换并弹出, 以此可以保证 指针稳定性 (该特性需要启用)真正的组件可能存储与另一个 密集数组 中, 也就是说 组件池 可能有一个 稀疏数组 二个 密集数组, 但我无法确定
还会使用 隐式链表 追踪
entt::tombstone参见 -
存储实体
存储实体时使用特化的 稀疏集, 可以看作是一个组件类型是 实体类型 的 特殊组件池, 在这种情况下, 它既没有entt::null也没有entt::tombstone, 而是在 稀疏数组 中维护一个 隐式链表 用于加速 标识符回收最新版本已经不使用隐式链表, 而是使用稀疏集在 密集数组 中使用分区 参见
标识符回收
为什么需要标识符回收? 想象一下, 如果不重复利用实体标识符, 那么将导致 稀疏数组 中的空洞越来越多, 而新建实体将不断增长 稀疏数组 的大小
甚至在一些原本很小的组件池中, 突然为一个标识符很大的实体附加组件, 将会导致该组件池的 稀疏数组 瞬间扩容至至少该标识符大小的长度
所以 实体 存储即使从来不会删除实体, 但是会在 实体 被 摧毁 时对其执行回收而不是删除, 被回收意味着可以被新创建的实体再次利用, 新创建的实体如果使用了回收的实体, 则会将其版本号增长, 显然这是因为 标识符 ID 无法进行修改, 只能通过修改版本号来区分之前的实体已经被摧毁失效, 当前的实体是新创建的