1个不稳定版本
0.9.1 |
|
---|
在游戏开发中排名1825
每月下载次数65次
在8个包中使用(3 直接使用)
265KB
5.5K SLoC
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, (mut number, flag)) in world.query::<(&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 模式还能提供出色的速度和缓存局部性。内部跟踪具有相同组件的实体组。每个组都有一个密集且连续的数组来存储每种类型的组件。当系统访问具有特定组件集的所有实体时,可以通过具有那些组件超集的每个组进行快速的线性遍历。这实际上是一个列式数据库,具有相同的优点:CPU 可以准确预测内存访问,绕过不需要的数据,最大化缓存使用并最小化延迟。
为什么不选择 ECS?
hecs 致力于轻量级和无干扰,以便在广泛的应用程序中发挥作用。即便如此,它并不适用于每款游戏。如果你的游戏将只有少量类型的实体,可以考虑更简单的架构,例如将每种类型的实体存储在单独的普通 Vec
中。同样,对于不需要批量处理实体的游戏,ECS 可能过于复杂。
即使对于受益于 ECS 的游戏,ECS 世界也不是万能的数据结构。大多数游戏将在其他结构中存储大量的状态。例如,许多游戏维护一个空间索引结构(例如瓦片地图或边界体积层次结构),用于在特定位置查找实体和障碍物,以实现高效的碰撞检测而无需搜索整个世界。
如果您需要使用除组件类型之外的准则来搜索特定实体,请考虑在您的世界中维护一个专门的索引,存储 Entity
处理程序和任何其他必要的数据。在创建相关实体时插入索引中,并包括一个组件,允许在销毁时有效地从索引中删除它们。
其他库
hecs 非常感谢 Rust 的 ECS 库生态系统中思想的自由交流。特别有影响力的是以下示例:
如果您不适用 hecs,这些中的一个可能会帮到您!
许可证
在以下任一许可下授权:
- Apache 许可证 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 拥有的代码。
依赖项
~2MB
~28K SLoC