magma_ecs 0.4.1

Entity-Component-System for the Magma3D game engine
Documentation

Magma-ECS

Magma-ECS is the Entity-component-system developed for the Magma3D engine. It aims to be simple to use and lightweight. It also provides an easy way for parallel execution of systems.

Even though this is intended for the magma_api it is easily possible to use on it's own.

Features

  • Efficient component storage using roaring bitmaps.
  • Multithreading using parking_lot's RwLock and rayon's parallel iterators.
  • Easy and ergonimic querying.
  • Creating system dispatchers that allow for parallel execution of systems, with the possibility to depend on other systems.
  • Support for global resources.
  • Event system

Usage

Add the crate to your Cargo.toml:

[dependencies]
magma_ecs = "0.4.0"

Entity-Component-System

Entity: An entity is just an index into the component storage.
Component: A component holds some type of data. Entities can have components assigned to them.
System: A system is a piece of code (usually a function), that reads and modifies the data.

Another way to think about this would be Identifier-Data-Logic.

Example

use magma_ecs::World;

fn main() -> Result<(), Box<dyn Error>> {
    // Create a world.
    let mut world = World::new();

    // Register components in the world.
    world.register_component::<Position>();
    world.register_component::<Health>();
    world.register_component::<Speed>();

    // Add a global resource.
    world.add_resource(GlobalDirection(1.0, 0.0, 0.0))?;

    // create a couple of entities
    for z in 0..10 {
        world.create_entity((Position(0.0, 0.0, z as f32), Health(20), Speed(1.0)))?;
    }

    // Create a system dispatcher.
    let dispatcher = Systems::new()
        .with(update_position, "update_position".to_string, vec![])
        .build_dispatcher();

    // Run the dispatcher.
    loop {
        dispatcher.dispatch(&world);
    }
}

// Components can be any type that is `Sync + Send`,
// or just any if you disabled the multithreading feature.
struct Position(f32, f32, f32);
struct Health(u32);
struct Speed(f32);

// The same applies to resources.
struct GlobalDirection(f32, f32, f32);

// Systems are ordinary functions, that take &World as a parameter.
fn update_position(world: &World) {
    let global_dir = world.get_resource::<GlobalDirection>().unwrap();

    world.query::<(Position, Speed)>().unwrap().iter().for_each(|entity| {
        let global_dir = world.get_resource::<GlobalDirection>().unwrap();
        let speed = entity.get_component::<Speed>().unwrap();
        let position = entity.get_component_mut::<Position>().unwrap();

        *position.0 += *global_dir.0 * *speed;
        *position.1 += *global_dir.1 * *speed;
        *position.2 += *global_dir.2 * *speed;
    });
}

Cargo Features

  • multithreading: Multithreading is enabled by default.
    • It also reexports rayon for your convinience.
  • track_deleted_entities: Don't allow assigning and deleting components to deleted entities

Disclaimer

This is still in developement and not production ready.