1个不稳定版本
0.0.1 | 2022年6月29日 |
---|
#13 in #hecs
265KB
5K SLoC
hexz
🚧 我自己的hecs分支 🚧
目前的差异
- 单类型资源
hecs提供了一个高性能、极简主义的实体-组件-系统(ECS)世界。它是一个库,而不是一个框架。在显式的"系统"抽象代替之处,可以使用常规代码轻松查询World
的实体。按照您喜欢的任何方式组织您的应用程序!
示例
let mut world = World::new();
// Nearly any type can be used as a component with zero boilerplate
let a = world.spawn((123, true, "abc"));
let b = world.spawn((42, false));
// Systems can be simple for loops
for (id, (number, &flag)) in world.query_mut::<(&mut i32, &bool)>() {
if flag { *number *= 2; }
}
// Random access is simple and safe
assert_eq!(*world.get::<i32>(a).unwrap(), 246);
assert_eq!(*world.get::<i32>(b).unwrap(), 42);
为什么选择ECS?
实体-组件-系统架构使得组合松散耦合的状态和行为变得容易。ECS世界由以下组成
- 任何数量的 实体,代表不同的对象
- 与每个实体关联的一组组件数据,其中每个实体最多有一种类型的组件,并且两个实体可能具有不同的组件
然后通过 系统 来操作这个世界,每个系统访问具有特定组件类型集合的所有实体。系统实现自包含的行为,如物理(例如,通过访问"位置"、"速度"和"碰撞"组件)或渲染(例如,通过访问"位置"和"精灵"组件)。
可以在不干扰现有逻辑的情况下向复杂的应用程序添加新的组件和系统,这使得ECS范式非常适合在相同对象集上定义多个重叠行为的应用程序,尤其是如果将来将添加新的行为。这种灵活性使其与传统方法截然不同,传统方法基于显式定义的对象类型的异构集合,实现新的行为组合(例如,既是车辆又是任务提供者)可能需要广泛的变化。
性能
除了具有出色的可组合性之外,ECS范式还可以提供出色的速度和缓存局部性。内部跟踪具有相同组件的实体组hecs
。每个组都有一个密集的、连续的数组,用于每种类型的组件。当系统访问具有特定组件集合的所有实体时,可以通过包含这些组件的超集的每个组进行快速的线性遍历。这实际上是一个列式数据库,具有相同的优点:CPU可以准确地预测内存访问,绕过不需要的数据,最大化缓存使用并最小化延迟。
为什么不是ECS?
hecs致力于轻量级和非侵入性,以便能够在广泛的领域中发挥作用。尽管如此,它并不适用于所有游戏。如果你的游戏只有少数几种实体类型,可以考虑使用更简单的架构,例如将每种类型的实体存储在单独的平面Vec
中。同样,对于不需要批量处理实体的游戏,ECS可能过于复杂。
即使对于受益于ECS的游戏,ECS世界也不是万能的数据结构。大多数游戏会在其他结构中存储大量的状态。例如,许多游戏维护一个空间索引结构(例如瓦片地图或边界体积层次结构),用于在特定位置附近查找实体和障碍物,从而在不搜索整个世界的情况下进行高效碰撞检测。
如果你需要使用除组件类型以外的标准来搜索特定实体,考虑在你的世界中维护一个专门的索引,存储Entity
句柄以及所需的其他数据。在生成相关实体时插入索引,并包括一个组件,允许在销毁实体时有效地从索引中删除。
其他库
hecs在很大程度上得益于Rust ECS库生态系统中思想的自由交流。特别有影响力的例子包括
如果你不适应hecs,那么这些中的任何一个可能都是解决方案!
许可证
许可方式为以下之一
- Apache License,版本2.0,(LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非你明确表示,否则根据Apache-2.0许可证定义的,你有意提交并包含在工作中的任何贡献,将按照上述方式双重许可,没有任何附加条款或条件。
免责声明
这不是一个官方的Google产品(实验性的或其他),这只是恰好由Google拥有的代码。
依赖
~1–1.3MB
~21K SLoC