We're happy to announce a new release of Specs, a highly parallel ECS.
It's been three months since the 0.8 version, which brought ticketed locks to you. Since then, there were many, many changes including
- integration of
shred
(PR) - a new book to get you started with Specs (PR)
- iterating over components in parallel (PR)
- better documentation
- a
FlaggedStorage
(PR) - a website for Specs, hosting the docs and the rendered book
Note: I'm leaving the old link here, but by now (09/2018) we've dropped the extra website and we now just use the book instead. So unless you want to admire the old (ugly) website, please visit slide-rs.github.io.
Additionally, we set up bors-ng, a GitHub application ensuring an evergreen master, similar to what @bors does in the Rust repos.
The new API utilizes "Aspects" to speed up system execution and get rid of all locks that were previously involved. Aspects are a way of telling Specs to which components a system needs read and to which write access. This is how it looks in code:
struct SysA;
impl<'a> System<'a> for SysA {
type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>);
fn run(&mut self, data: Self::SystemData) {}
}
With that knowledge, Specs (or more acccurately, shred
) can build up certain stages, to put it simply, a data structure which tells us
- in which order systems can be executed and
- which systems may run in parallel
After that, we make use of rayon's power to execute them in parallel.
This is an example of setting up these systems:
let mut d = DispatcherBuilder::new()
.add(RequestSpawns, "req_spawns", &[])
.add(GenCollisions, "gen_collisions", &[])
.add(SpawnEnemies, "spawn", &["req_spawns"]) // we can specify dependencies between systems
.add_barrier()
.add(Integrate, "integrate", &[])
.build();
You think executing the systems in parallel isn't enough? No, problem, let's do the same for the components:
impl<'a> System<'a> for UpdatePos {
type SystemData = (WriteStorage<'a, Pos>, ReadStorage<'a, Vel>);
fn run(&mut self, data: Self::SystemData) {
use rayon::prelude::*;
let (mut pos, vel) = data;
(&mut pos, vel)
.par_join()
.for_each(|(pos, vel)| pos.0 += vel.0);
}
}
Want to learn more about it? Then just start with the Hello World chapter. If you need any help, please join us on Gitter.