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!
```rust use sparsey::prelude::*;
// Components are Send + Sync + 'static types. struct Position(f32); struct Velocity(f32); struct Immovable;
// Sets the Velocity of Immovable entities to zero.
fn update_velocity(mut vel: CompMut
// Adds the Velocity of each entity to its Position.
fn update_position(mut pos: CompMut
fn main() { // Create a World to store our game data. let mut world = World::default();
// Create a Dispatcher to run our systems.
let mut dispatcher = Dispatcher::builder()
.add_system(update_velocity.system())
.add_system(update_position.system())
.build();
// Register all component types we want to use.
dispatcher.register_storages(&mut world);
// Create some entities.
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));
// Run the systems 3 times.
for _ in 0..3 {
dispatcher.run_seq(&mut world).unwrap();
world.increment_tick();
}
} ```
Systems are plain functions that may return a SystemResult
to signal errors.
```rust
fn printaliveentities(hp: Comp
fn saveentities(savefile: ResMut
Ok(())
} ```
Get, include, exclude and filter components using Sparsey's query API.
```rust
fn queries(a: Comp, b: Comp, c: Comp
// Iter components A from entities with A and B.
for a in (&a).include(&b).iter() {}
// Iter components A from entities with A and without B.
for a in (&a).exclude(&b).iter() {}
// Iter components A from entities with A and B, without C.
for a in (&a).include(&b).exclude(&c).iter() {}
// Iter components A from entities with A and B, without C and with D xor E.
for a in (&a).include(&b).exclude(&c).filter(contains(&d) ^ contains(&e)).iter() {}
} ```
Filter queries based on whether or not a component or component set was changed.
```rust
fn change_detection(a: Comp, b: Comp, c: Comp
// Iter A, B component sets where A or B was changed.
for (a, b) in changed((&a, &b)).iter() {}
// Iter A, B, C component sets where A or B was changed and C was changed.
for ((a, b), c) in (changed((&a, &b)), changed(&c)).iter() {}
} ```
Sparsey allows the user to "group" component storages to greatly optimize iteration performance.
Groups are created by setting a Layout
on the World
.
```rust
let layout = Layout::builder()
.addgroup(<(A, B)>::group())
.addgroup(<(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.
```rust
fn denseiterators(a: Comp, b: Comp, c: Comp
// These would panic if the storages weren't grouped.
let _: &[Entity] = (&a, &b).entities().unwrap();
let _: (&[A], &[B]) = (&a, &b).components().unwrap();
let _: (&[Entity], (&[A], &[B])) = (&a, &b).entities_components().unwrap();
} ```
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!
Sparsey is dual-licensed under either * MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT) * Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
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.