Expand description
§Tiny ECS
The intention of this crate is that a basic ECS is provided, where you will be required to exercise a little additional control.
Where most other ECS crates provide a mechanism for inserting “systems” in to the ECS to run against entities, this one leaves it out - you can think of it as a “system for entity/components”. You will need to create external systems; these can be a function, a loop, or anything else.
Internally this ECS is the use of bitmasks
. Each entity ID is in
practice an internal index number in to an array which contains bitmasks.
The bitmasks themselves keep track of what components the entity has.
Note: borrows of Persist
are checked at runtime, but there are also
some unchecked borrows provided.
§Examples
§Demonstrating use
use tiny_ecs::Entities;
use tiny_ecs::ECSError;
// These are the "components" we will use
struct Vector1 {
x: i32,
}
struct Vector2 {
x: i32,
y: i32,
}
struct Vector3 {
x: i32,
y: i32,
z: i32,
}
// Initialize the Entity collection
let mut entities = Entities::new(Some(3), Some(3));
// Creating an entity uses the builder pattern.
// Be sure to return the ID if you need to track it
let entity_1 = entities.new_entity()
.with(Vector1 { x: 42 })?
.with(Vector3 { x: 3, y: 10, z: -12 })?
.finalise()?;
// The entity ID will increment up from 0
assert_eq!(entity_1, 0);
// Do note however, that you can keep adding parts to this entity
// via the builder pattern until you choose to create another entity
// To add another entity you need to create one
entities.new_entity()
.with(Vector2 { x: 66, y: 6 })?
.with(Vector1 { x: 6 })?
.finalise()?;
§Access an entities part of type <T>
struct Vector3 {x: i32, y: i32, z: i32 }
// To get access to a part belonging to an entity you need
// first to get the component map created for the part type
// You need to 'anchor' this with a let or the ref is
// dropped before you can use it
let mut components = entities
.borrow_mut::<Vector3>()?;
// You can then use the part by getting a reference
let mut part = components.get_mut(entity_1).unwrap();
assert_eq!(part.z, -12);
§Check if Entity
contains a part type + remove part
struct Vector1 {x: i32 }
let entity_1 = entities.new_entity()
.with(Vector1 { x: 3 })?
.finalise()?;
// You can check if an entity contains a part with the type signature
if entities.entity_contains::<Vector1>(entity_1) {
assert!(entities.rm_component_from::<Vector1>(entity_1).is_ok());
}
assert_eq!(entities.entity_contains::<Vector1>(entity_1), false);
§A system that uses an get_mut()
struct Vector1 {x: i32 }
// Make a system of some form that takes a `Persist<T>` arg
fn some_system(mut components: &mut Persist<Vector1>) {
// You can then iterate over the components directly
for (k, v) in components.iter_mut().enumerate() {
v.x += 1;
assert!(v.x > k as i32);
}
}
some_system(&mut components);
§Get components for an entity ID list
struct Vector1 {x: i32 }
// A system that fetches the components for only the entities you are require
fn second_system(active: &[usize], mut v1_map: &mut Persist<Vector1>) {
for id in active {
if let Some(part) = v1_map.get_mut(*id) {
part.x = 42;
}
}
}
second_system(&[0, 1, 2], &mut components);
§A more complex system using Persists directly
// Or a system handles the `Entities` container directly
fn other_system(active_ents: &[usize], entities: &mut Entities) -> Result<(), ECSError> {
// You can mutably borrow multiple component maps at once
let mut v1_components = entities
.borrow_mut::<Vector1>()?;
let mut v2_components = entities
.borrow_mut::<Vector2>()?;
// But not have a mutable borrow and immutable borrow to the same map
// Fails at runtime!
// let v2_components = entities.borrow::<Vector2>().unwrap();
for id in active_ents {
if entities.entity_contains::<Vector1>(*id) &&
entities.entity_contains::<Vector2>(*id) {
let v1_part = v1_components.get_mut(*id).unwrap();
let v2_part = v2_components.get_mut(*id).unwrap();
v1_part.x = 42;
assert_ne!(v1_part.x, 43);
assert_eq!(v1_part.x, 42);
}
}
Ok(())
}
other_system(&[0, 1, 2], &mut entities);
Structs§
- This is the root of the ECS implementation
- Immutable reference container for
Persist
returned byEntities::borrow()
- Mutable reference container for
Persist
returned byEntities::borrow_mut()
- Iteration will not always be in order