#ecs #game-engine #gamedev #debugging

xecs

一个实体-组件-系统库

26个版本

0.5.10 2022年4月8日
0.5.8 2022年3月31日
0.3.3 2021年10月21日

541游戏开发

Download history 6/week @ 2024-03-12 1/week @ 2024-03-26 17/week @ 2024-04-02

每月 99 次下载
4 crates 中使用

MIT 协议

170KB
3.5K SLoC

XECS

一个实体-组件-系统库

简单示例

// Define two components struct
// Component is Send + Sync + 'static
#[derive(Debug,Copy)]
struct Position{
    x : f32,
    y : f32
};
struct Hidden;

// create an empty world
let mut world = World::new();

// generate 10 entities
for _ in 0..10 {
    let x = random();
    lety = random();
    // andomly generate the positions
    world.create_entity()
        .attach(Position { x,y });
}

// print all postions
for pos in world.query::<&Position>() {
    print!("{:?}",pos)
}

// filter some entities need to be hidden
let ids = world.query::<&Position>()
    .with_id()
    .filter(|(_,_)|random())
    .map(|(id,_)|id)
    .collect::<Vec<_>>();

// attach hidden to id
for id in ids {
    world.attach_component(id,Hidden);
}

// make a full-owning group to accelerate the query
world.make_group(full_owning::<Hidden,Position>());

// only print postions with id that is not hidden
for (id,data) in world.query::<&Position,Without<&Hidden>>() {
    print!("{}:{:?}",id,data);
}

关于实体

在XECS中,实体只是一个数字ID。在XECS中,它只是一个 NonZeroUsize。ID由世界自动分配,从1开始。通过 Option<EntityId>id=0 代表一个没有其他标记的回收ID。

ID回收

当你调用 world.create_entity() 时,会自动分配一个ID。如果你调用 world.remove_entity(id),这个ID将成为一个空位。如果下一个 world.create_entity() 被调用,它将分配这个ID来填充空位。由于使用了稀疏集合,无论ID多么随机,迭代所有组件仍然很快。

并发安全性

因为 组件 只是 T : Send + Sync世界 可以使用 RwLock 来确保所有组件的借用检查关系。并且 世界 也可以是 Send + Sync。因此,所有其他世界状态都可以由 RwLock 保护。所以我们可以通过 RwLock<World> 在并发环境中使用世界。

XECS中的系统

系统是一个以 World 为上下文的 Stream。由于 Streamstd 中不稳定,XECS使用 futures::Stream 代替。

运行系统

因为系统只是一个异步特质,你需要从tokioasync-std获取运行时的包装器。

依赖项

~1–6MB
~27K SLoC