10个不稳定版本 (3个破坏性更改)
0.4.0 | 2021年2月25日 |
---|---|
0.3.1 | 2020年9月28日 |
0.2.4 | 2020年6月19日 |
0.2.1 | 2019年12月5日 |
0.1.1 | 2019年3月9日 |
#203 in 游戏开发
每月下载量2,722
在 25 个包 中使用 (16 个直接使用)
1MB
11K SLoC
Legion旨在为Rust游戏项目提供一个功能丰富的高性能实体组件系统(ECS)库,具有最少的样板代码。
入门指南
世界
世界 是一组 实体 的集合,其中每个实体可以附加任意数量的 组件。
use legion::*;
let world = World::default();
实体可以通过 push
(用于单个实体)或 extend
(用于具有相同组件类型的实体集合)来插入。世界将为每个插入的实体创建一个唯一的ID,以便您可以稍后引用该实体。
// a component is any type that is 'static, sized, send and sync
#[derive(Clone, Copy, Debug, PartialEq)]
struct Position {
x: f32,
y: f32,
}
#[derive(Clone, Copy, Debug, PartialEq)]
struct Velocity {
dx: f32,
dy: f32,
}
// push a component tuple into the world to create an entity
let entity: Entity = world.push((Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }));
// or extend via an IntoIterator of tuples to add many at once (this is faster)
let entities: &[Entity] = world.extend(vec![
(Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }),
(Position { x: 1.0, y: 1.0 }, Velocity { dx: 0.0, dy: 0.0 }),
(Position { x: 2.0, y: 2.0 }, Velocity { dx: 0.0, dy: 0.0 }),
]);
您可以通过 entries 访问实体。条目允许您查询实体附加了哪些类型的组件,获取组件引用,或添加和删除组件。
// entries return `None` if the entity does not exist
if let Some(mut entry) = world.entry(entity) {
// access information about the entity's archetype
println!("{:?} has {:?}", entity, entry.archetype().layout().component_types());
// add an extra component
entry.add_component(12f32);
// access the entity's components, returns `None` if the entity does not have the component
assert_eq!(entry.get_component::<f32>().unwrap(), &12f32);
}
查询
条目不是搜索或批量访问世界的最方便或最高效的方式。 查询 允许以高性能和表达性强的方式遍历世界中的实体。
// you define a query be declaring what components you want to find, and how you will access them
let mut query = <&Position>::query();
// you can then iterate through the components found in the world
for position in query.iter(&world) {
println!("{:?}", position);
}
您可以根据一组组件搜索实体。
// construct a query from a "view tuple"
let mut query = <(&Velocity, &mut Position)>::query();
// this time we have &Velocity and &mut Position
for (velocity, position) in query.iter_mut(&mut world) {
position.x += velocity.x;
position.y += velocity.y;
}
您可以在基本查询上添加额外的过滤器。例如,您可以选择排除包含特定组件的实体,或者只包括在查询运行以来某个组件已更改的实体(此过滤是保守的,粒度较粗)。
// you can use boolean expressions when adding filters
let mut query = <(&Velocity, &mut Position)>::query()
.filter(!component::<Ignore>() & maybe_changed::<Position>());
for (velocity, position) in query.iter_mut(&mut world) {
position.x += velocity.dx;
position.y += velocity.dy;
}
查询还有更多功能。有关更多信息,请参阅模块文档。
系统
你可能已经注意到,当我们想要写入一个组件时,我们需要使用 iter_mut
来遍历我们的查询。但是,也许你的应用程序希望能够在不同的实体上处理不同的组件,甚至可能是同时并行处理?虽然手动操作是可能的(参见 World::split),但是当应用程序的不同部分不知道彼此需要什么组件,或者可能有或可能没有冲突的访问需求时,这样做是非常困难的。
系统 和 调度器 自动化了这个过程,甚至可以在比手动操作更细粒度的层面上进行调度。系统是工作单元。每个系统都被定义为一个函数,它提供了访问查询和共享 资源 的权限。然后,可以将这些系统添加到调度器中,调度器是系统的线性序列,按照观察副作用(如写入组件)的时间顺序排列。调度器将自动并行执行所有系统,同时保持每个系统从其自身视角看来的执行顺序。
// a system fn which loops through Position and Velocity components, and reads the Time shared resource
// the #[system] macro generates a fn called update_positions_system() which will construct our system
#[system(for_each)]
fn update_positions(pos: &mut Position, vel: &Velocity, #[resource] time: &Time) {
pos.x += vel.dx * time.elapsed_seconds;
pos.y += vel.dy * time.elapsed_seconds;
}
// construct a schedule (you should do this on init)
let mut schedule = Schedule::builder()
.add_system(update_positions_system())
.build();
// run our schedule (you should do this each update)
schedule.execute(&mut world, &mut resources);
特性标志
Legion 提供了一些特性标志
parallel
- 通过 rayon 库启用并行迭代器和并行调度执行。默认启用。extended-tuple-impls
- 将视图和组件元组的最大大小从 8 扩展到 24,但会增加编译时间。默认关闭。serialize
- 启用 serde 序列化模块和相关功能。默认启用。crossbeam-events
- 实现了 crossbeamSender
通道的EventSender
特性,允许它们用于事件订阅。默认启用。
WASM
Legion 默认启用并行性,但目前 Web Assembly 不支持并行,因为它以单线程运行。因此,为了为 WASM 编译,请确保在 Cargo.toml 中设置 default-features = false
。此外,如果你想要使用 serialize
特性,你必须启用 stdweb
或 wasm-bindgen
特性,这些特性将通过 uuid
包进行代理。有关更多信息,请参阅 uuid 包。
legion = { version = "*", default-features = false, features = ["wasm-bindgen"] }
依赖项
~1.6–3MB
~59K SLoC