[−][src]Crate tiny_ecs
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. This is somewhat due to some limitations, and also due to trying to maintain as little overhead as possible - this means no unneccesary copies/clones.
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.
Attention: borrows of ComponentMap
are checked at runtime.
Attention: this crate will panic in many cases if used incorrectly. This is intentional to prevent many kinds of bugs and to encourage you to define behaviour well.
Examples
Init with a capacity
This is good to do if you know the size required as it will prevent many reallocs/moves as data is added. This affects both the entity and component map allocs (they will be equal in length).
use tiny_ecs::Entities; let mut entities = Entities::new(Some(1000), Some(24));
Demonstrating use
use tiny_ecs::Entities; // 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_part(Vector1 { x: 42 }) .with_part(Vector3 { x: 3, y: 10, z: -12 }) .finalise(); assert!(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_part(Vector2 { x: 66, y: 6 }) .with_part(Vector1 { x: 6 });
The builder pattern is powerful
let ent = world .entities
.new_entity()
.with_part(ParticleID { id })
.with_part(Sprite::new(sprite_id, rec))
.with_part(InputTypes::Player(binds))
.with_part(Player::new(5.0, 15.0))
.finalise();
Access an entities part of type <T>
// 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>() .unwrap(); // You can then use the part by getting a reference let mut part = components.get_part_mut(entity_1).unwrap(); assert_eq!(part.z, -12);
Check if Entity
contains a part type + remove part
let entity_1 = entities.new_entity() .with_part(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_part::<Vector1>(entity_1).is_ok()); } assert_eq!(entities.entity_contains::<Vector1>(entity_1), false);
A system that uses an get_mut()
// Make a system of some form that takes a `ComponentMap<T>` arg fn some_system(mut components: &mut ComponentMap<Vector1>) { // You can then iterate over the components directly for (k, v) in components.get_mut() { v.x += 1; assert!(v.x > k as i32); } } some_system(&mut components);
Get components for an entity ID list
// A system that fetches the components for only the entities you are require fn second_system(active: &[usize], mut v1_map: &mut ComponentMap<Vector1>) { for id in active { if let Ok(part) = v1_map.get_part_mut(*id) { part.x = 42; } } } second_system(&[0, 1, 2], &mut components);
A more complex system using ComponentMaps directly
// Or a system handles the `Entities` container directly fn other_system(active_ents: &[usize], entities: &mut Entities) { // You can mutably borrow multiple part types at once let mut v1_components = entities .borrow_mut::<Vector1>() .unwrap(); let mut v2_components = entities .borrow_mut::<Vector2>() .unwrap(); // But not have a mutable borrow and immutable borrow to the same // Fails at runtime! // let v2_components = entities.borrow::<Vector2>().unwrap(); // But you can have multiple immutable references to the same part for id in active_ents { if entities.entity_contains::<Vector1>(*id) && entities.entity_contains::<Vector2>(*id) { let v1_part = v1_components.get_part_mut(*id).unwrap(); let v2_part = v2_components.get_part_mut(*id).unwrap(); v1_part.x = 42; assert_ne!(v1_part.x, 43); assert_eq!(v1_part.x, 42); } } } other_system(&[0, 1, 2], &mut entities);
Structs
ComponentMap |
|
Entities | This is the root of the ECS implementation |
MapRef | Immutable reference container for |
MapRefMut | Mutable reference container for |
Enums
ECSError |
Constants
EMPTY |