6 个版本

0.2.2 2021 年 9 月 23 日
0.2.1 2021 年 9 月 23 日
0.2.0 2021 年 3 月 20 日
0.1.1 2021 年 3 月 15 日
0.0.0 2017 年 10 月 10 日

#1215 in Rust 模式

MIT/Apache

33KB
696

Genesis - 一个 ECS 生成库

Documentation Crates.io

概述

genesis 提供了一个 ECS 生成宏。
与其他在运行时进行动态借用检查的 ECS 库和框架不同,你事先定义所有组件,生成一个完全静态类型的 ECS,借用检查在编译时进行。
不再需要在函数间传递 World,以避免遇到动态借用检查问题!

genesis 是一个轻量级的 ECS 库,不提供任何调度功能。相反,你可以直接查询每个组件类型的存储。

use genesis::*;

#[derive(Clone, Debug, Eq, PartialEq)]
struct IndexComponent {
    index: usize,
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct NameComponent {
    name: String,
}

#[derive(Clone, Debug, Eq, PartialEq)]
struct RareComponent {
    data: u32,
}

#[world(MyComponent, Template)]
#[derive(Clone, Debug, Eq, PartialEq)]
struct World {
    #[component(vec)] //default, optional
    #[template_name(index)]
    indices: IndexComponent,
    #[template_name(name)]
    names: NameComponent,
    #[component(map)]
    rare_data: RareComponent,
}

fn main() -> Result<(), NoSuchEntity> {
    let initial_capacity = 1024;
    let mut world = World::new(initial_capacity);

    // spawn an entity
    let id_a = world.spawn();
    // set the components directly on the corresponding storage
    world.indices.set(id_a, IndexComponent { index: 42 })?;

    // spawn another entity
    let id_b = world.spawn();
    // alternative way to set components: using the utility trait Register<T>.
    world.register(id_b, IndexComponent { index: 0 })?;
    world.register(
        id_b,
        NameComponent {
            name: String::from("B"),
        },
    )?;

    let id_c = world.spawn();
    // third way of setting components: using the generated Template struct.
    world.register(
        id_c,
        Template {
            index: Some(IndexComponent { index: 100 }),
            ..Default::default()
        },
    )?;

    if let Some(a_index) = world.indices.get(id_a) {
        println!("first entity has index {:?}", a_index);
    }

    for id in world.entities.read().unwrap().iter() {
        if let Some(index) = world.indices.get(id) {
            println!("entity {:?} has index {:?}", id, index);
        }
    }

    Ok(())
}

目标

genesis 的主要目标是提供一个具有编译时借用检查的类型安全 ECS。
这有助于避免编写在循环遍历实体时传递 ECS 世界到另一个函数,同时保留调用函数中的可变引用的代码,这会导致运行时借用检查问题。

其他 ECS

Rust 中有很多不同的 ECS,各有优缺点。特别是检查这些

基准测试

性能不是 genesis 的主要目标;ECS 的主要优势是这种范式所支持的数据建模。
如果你有严重的时间限制,并且需要遍历数十万个实体,你应该考虑使用像 hecs 这样的架构 ECS,以获得更好的迭代速度,这是通过更好的数据局部性和缓存友好性实现的。请注意,基于架构的 ECS 通常在添加/删除组件方面以更差的性能换取更好的迭代时间,与像 specsgenesis 这样的 ECS 相比,它们有不同的存储。有关更多信息,请参阅 基准测试

许可

许可协议

  • MIT 许可证
  • Apache 许可证 2.0

贡献

欢迎贡献!除非明确说明,否则你的贡献将被假设为与 genesis 相同的许可证(见上方)。

依赖项

~1.5MB
~41K SLoC