sparsey-0.6.0 has been yanked.
Sparsey

Sparsey is a sparse set-based Entity Component System with lots of features and nice syntax
~( ˘▾˘~)
Check out the Sparsey Cheat Sheet and examples to get
started!
Example
use sparsey::prelude::*;
struct Position(f32);
struct Velocity(f32);
struct Immovable;
fn update_velocity(mut vel: CompMut<Velocity>, imv: Comp<Immovable>) {
for mut vel in (&mut vel).include(&imv).iter() {
vel.0 = 0.0;
}
}
fn update_position(mut pos: CompMut<Position>, vel: Comp<Velocity>) {
for (mut pos, vel) in (&mut pos, &vel).iter() {
pos.0 += vel.0;
}
}
fn main() {
let mut world = World::default();
let mut dispatcher = Dispatcher::builder()
.add_system(update_velocity.system())
.add_system(update_position.system())
.build();
dispatcher.register_storages(&mut world);
world.create_entity((Position(0.0), Velocity(1.0)));
world.create_entity((Position(0.0), Velocity(2.0)));
world.create_entity((Position(0.0), Velocity(3.0), Immovable));
for _ in 0..3 {
dispatcher.run_seq(&mut world).unwrap();
world.increment_tick();
}
}
Features
Easy to Write Systems
Systems are plain functions that may return a SystemResult to signal errors.
fn print_alive_entities(hp: Comp<Hp>) {
for (entity, hp) in (&hp).iter().entities() {
if hp.0 > 0 {
println!("{:?} - {:?}", entity, hp);
}
}
}
fn save_entities(save_file: ResMut<SaveFile>, position: Comp<Position>) -> SystemResult {
for (entity, position) in (&position).iter().entities() {
save_file.save_entity_with_position(entity, position)?;
}
Ok(())
}
Expressive Queries
Get, include, exclude and filter components using Sparsey's query API.
fn queries(a: Comp<A>, b: Comp<B>, c: Comp<C>, d: Comp<D>, e: Comp<E>) {
for (a, b) in (&a, &b).iter() {}
for a in (&a).include(&b).iter() {}
for a in (&a).exclude(&b).iter() {}
for a in (&a).include(&b).exclude(&c).iter() {}
for a in (&a).include(&b).exclude(&c).filter(contains(&d) ^ contains(&e)).iter() {}
}
Granular Change Detection
Filter queries based on whether or not a component or component set was changed.
fn change_detection(a: Comp<A>, b: Comp<B>, c: Comp<C>, d: Comp<D>, e: Comp<E>) {
for a in changed(&a).iter() {}
for (a, b) in changed((&a, &b)).iter() {}
for ((a, b), c) in (changed((&a, &b)), changed(&c)).iter() {}
}
Great Performance with Grouped Storages
Sparsey allows the user to "group" component storages to greatly optimize iteration performance.
Groups are created by setting a Layout on the World.
let layout = Layout::builder()
.add_group(<(A, B)>::group())
.add_group(<(A, B, C, D>)>::group())
.build();
let world = World::with_layout(&layout);
After the layout is set, iterators over the grouped storages become "dense", greatly improving their
performance. Additionally, grouped storages allow access to their components and entities as slices.
fn dense_iterators(a: Comp<A>, b: Comp<B>, c: Comp<C>, d: Comp<D>) {
assert!((&a, &b).iter().is_dense());
assert!((&a, &b, &c, &d).iter().is_dense());
assert!((&a, &b).exclude((&c, &d)).iter().is_dense());
let _: &[Entity] = (&a, &b).entities().unwrap();
let _: (&[A], &[B]) = (&a, &b).components().unwrap();
let _: (&[Entity], (&[A], &[B])) = (&a, &b).entities_components().unwrap();
}
Thanks
Sparsey takes inspiration and borrows features from other free and open source ECS projects, namely
Bevy, EnTT,
Legion, Shipyard and
Specs. Make sure you check them out!
License
Sparsey is dual-licensed under either
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the
work by you, as defined in the Apache-2.0 license, shall be dual licensed as above without any
additional terms or conditions.