6个版本 (3个重大更新)

0.12.1 2024年6月29日
0.12.0 2024年1月27日
0.11.1 2023年9月27日
0.11.0 2023年7月16日
0.5.0 2021年11月9日

#144 in 游戏开发

Download history 223/week @ 2024-06-28 9/week @ 2024-07-05 65/week @ 2024-07-26 7/week @ 2024-08-02

每月72次下载

MIT/Apache

145KB
4K SLoC

Sparsey

Crates.io Documentation

Sparsey是一个基于稀疏集的实体组件系统 (ECS)

设计目标

  • 灵活:任何 Send + Sync + 'static 类型都可以用作组件。
  • 简洁:最常用的功能应该需要最少的输入。
  • 利用稀疏集:提供仅适用于基于稀疏集的ECS的功能。

示例

use sparsey::prelude::*;

struct Position(f32);
struct Velocity(f32);

fn main() {
    let mut entities = EntityStorage::default();
    entities.register::<Position>();
    entities.register::<Velocity>();

    entities.create((Position(0), Velocity(1)));
    entities.create((Position(0), Velocity(2)));
    entities.create((Position(0), Velocity(3)));

    entities.run(|mut positions: CompMut<Position>, velocities: Comp<Velocity>| {
        (&mut positions, &velocities).for_each(|(position, velocity)| {
            position.0 += velocity.0;
        }); 
    });
}

特性

易于使用的系统

系统是普通的函数。

struct HealMultiplier(f32);

fn update_positions(mut positions: CompMut<Position>, velocities: Comp<Velocity>) {
    (&mut positions, &velocities).for_each(|(position, velocity)| {
        position.0 += velocity.0;
    });
}

fn update_hps(mut hps: CompMut<Hp>, heals: Comp<Heal>, heal_multipler: Res<HealMultiplier>) {
    (&mut hps, &heals).for_each(|(hp, heal)| {
        hp.0 += heal.0 * heal_multiplier.0;
    });
}

let mut world = World::default();
world.entities.register::<Position>();
world.entities.register::<Velocity>();
world.resources.insert(HealMultiplier(1.2));

world.run(update_positions);
world.run(update_hps);

丰富的查询

使用Sparsey的查询API获取、包含和排除组件。

fn queries(a: Comp<A>, b: Comp<B>, c: Comp<C>, d: Comp<D>, e: Comp<E>) {
    // Iter components A and B from entities with A and B.
    (&a, &b).for_each(|(a, b)| {
        // ... 
    });

    // Iter components A from entities with A and B.
    (&a).include(&b).for_each(|a| {
        // ...
    });

    // Iter components A from entities with A and without B.
    (&a).exclude(&b).for_each(|a| {
        // ...
    });

    // Iter components A from entities with A and B, without C.
    (&b).include(&b).exclude(&c).for_each(|a| {
        // ...
    });
}

分组存储的高性能

Sparsey允许用户“分组”组件存储,从而大大优化迭代性能。通过设置GroupLayout来创建分组。

let layout = GroupLayout::builder()
    .add_group::<(A, B)>()
    .add_group::<(A, B, C, D>)>()
    .build();

let entities = EntityStorage::new(&layout);

设置布局后,分组存储的迭代器变为“密集”,大大提高了其性能。此外,分组存储允许以切片的形式访问其组件和实体。

fn group_slices(a: Comp<A>, b: Comp<B>) {
    if let Some(entities) = (&a, &b).group_entities() {
        // ...
    }

    if let Some((a_slice, b_slice)) = (&a, &b).group_components() {
        // ...
    }

    if let Some((entities, (a_slice, b_slice))) = (&a, &b).group_data() {
        // ...
    }
}

感谢

Sparsey从其他免费和开源的ECS项目中获得灵感和借鉴特性,包括BevyEnTTLegionShipyardSpecs。请确保您检查它们!

许可证

Sparsey可以选择以下任一许可证

任选其一。


除非您明确声明,否则根据Apache-2.0许可证定义,您有意提交以包含在作品中的任何贡献,都应按上述方式双重许可,而无需附加任何条款或条件。

依赖关系

~45KB