Crate pyro

source ·
Expand description

What is an Entity Component System?

An Entity Component System or ECS is very similar to a relational database like * SQL*. The World is the data store where game objects (also known as Entity) live. An Entity contains data or Components. The ECS can efficiently query those components.

Give me all entities that have a position and velocity component, and then update the position based on the velocity.

type PosVelQuery = (Write<Pos>, Read<Vel>);
//                  ^^^^^       ^^^^
//                  Mutable     Immutable
world.matcher::<All<PosVelQuery>>().for_each(|(pos, vel)|{
    pos += vel;
})

Internals

// A Storage that contains `Pos`, `Vel`, `Health`.
(
   [Pos1, Pos2, Pos3, .., PosN],
   [Vel1, Vel2, Vel3, .., VelN],
   [Health1, Health2, Health3, .., HealthN],
)

// A Storage that contains `Pos`, `Vel`.
(
   [Pos1, Pos2, Pos3, .., PosM]
   [Vel1, Vel2, Vel3, .., VelM]
)

Iteration is fully linear with the exception of jumping to different storages.

The iteration pattern from the query above would be

positions:  [Pos1, Pos2, Pos3, .., PosN], [Pos1, Pos2, Pos3, .., PosM]
velocities: [Vel1, Vel2, Vel3, .., VelN], [Vel1, Vel2, Vel3, .., VelM]
                                        ^
                                        Jump occours here

The jump is something like a chain of two iterators. We look at all the storages that match specific query. If the query would be Write<Position>, then we would look for all the storages that contain a position array, extract the iterators and chain them

Every combination of components will be in a separate storage. This guarantees that iteration will always be linear.

Benchmarks

Getting started

Structs

Is satisfied when a storages contains all of the specified components.
The Iterator is used to end a borrow from a query like World::matcher.
Serves as an ID to lookup components for entities which can be in different storages.
Implements Fetch and allows components to be borrowed immutable.
Rust’s borrowing rules are not flexible enough for an ECS. Often it would prefered to nest multiple query like World::matcher, but this is not possible if both borrows would be mutable. Instead we track active borrows at runtime. Multiple reads are allowed but read/write and write/write are not.
A runtime SoA storage. It stands for Structure of Arrays.
World is the heart of this library. It owns all the Components and Storages. It also manages entities and allows Components to be safely queried.
Implements Fetch and allows components to be borrowed mutable.

Traits

BuildStorage is used to create different Storages at runtime. See also AppendComponents and World::append_components
A helper trait that works in lockstep with Read and Write to borrow components either mutable or immutable.
Allows to match over different Storages. See also All.
Is implemented for Read and Write and is used to insert reads and writes into the correct HashSet.
Allows to query multiple components from a Storage. See also All.
A Storage won’t have any arrays or vectors when it is created. RegisterComponent can register or add those component arrays. See also EmptyStorage::register_component
Storage allows to abstract over differnt types of storages. The most common storage that implements this trait is SoaStorage.

Type Definitions