Crate trex [] [src]

An entity component system inspired by entityx. The core of trex is the simulation! macro, which wires together all of the components, events, and systems. Entitys and Components are managed through the World interface. Events are queued and emitted through the Events interface, which is automatically generated by the simulation! macro.

Examples

A simple 2D physics simulation.

// lazy_static must be imported manually since Rust does not yet support re-exporting external
// macros.
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate trex;

use trex::*;

// The components used in the simulation.
pub struct Position { pub x: f32, pub y: f32 }
pub struct Velocity { pub dx: f32, pub dy: f32 }
pub struct Acceleration { pub ddx: f32, pub ddy: f32 }

pub struct PhysicsSystem {
    filter: ComponentFilter, // Used to select entities with the components of interest to this
                             // system.
}

impl System<Events> for PhysicsSystem {
    fn new() -> PhysicsSystem {
        PhysicsSystem {
            filter: ComponentFilter::new()
                .with::<Position>()
                .with::<Velocity>()
                .with::<Acceleration>(),
        }
    }

    fn update(&mut self, world: &mut World, events: &mut Events, dt: f32) {
        let dt_secs = dt / 1000.0;
        for entity in world.filter_entities(&self.filter) {
            assert!(world.has::<Position>(entity));
            assert!(world.has::<Velocity>(entity));
            assert!(world.has::<Acceleration>(entity));
            let (dx, dy) = {
                let &Acceleration { ddx, ddy } = world.get::<Acceleration>(entity).unwrap();
                let mut vel = world.get_mut::<Velocity>(entity).unwrap();
                vel.dx += ddx * dt_secs;
                vel.dy += ddy * dt_secs;
                (vel.dx, vel.dy)
            };
            let mut pos = world.get_mut::<Position>(entity).unwrap();
            pos.x += dx * dt_secs;
            pos.y += dy * dt_secs;
        }
        events.halt.emit(trex::Halt);
    }
}

simulation! {
    // The components section takes a set of `Type`: `STATIC` pairs. This maps the
    // component type to a unique family` used internally by trex`.
    components: {
        Position: POSITION,
        Velocity: VELOCITY,
        Acceleration: ACCELERATION
    },

    // The events section takes a set of `field`: `Type` pairs. This creates a new event queue
    // field on the Events object for the given event type.
    events: { },

    // The systems section takes a set of `field`: `System` pairs. This creates a new field on
    // the Simulation for the given system.
    systems: {
        physics: PhysicsSystem
    }
}

fn main() {
    let mut simulation = Simulation::new();

    simulation.setup(|world, events| {
        // Create an entity that accelerates in the x and y directions.
        let entity = world.create();
        world.tag(entity, "Test");
        world.add(entity, Position { x: 1.0, y: 2.0 });
        world.add(entity, Velocity { dx: 3.0, dy: 4.0 });
        world.add(entity, Acceleration { ddx: 5.0, ddy: 6.0 });
    });

    // Run a single iteration of the simulation.
    simulation.update(1000.0);

    let entity = simulation.world.lookup("Test").unwrap();
    let pos = simulation.world.get::<Position>(entity).unwrap();
    assert_eq!(pos.x, 9.0);
    assert_eq!(pos.y, 12.0);
    assert!(simulation.received_halt());
}

Macros

component!

Used to implement the component trait for a given type. This macro should never be called manually. Concrete components should be passed into the simulation! macro, which will call this macro.

simulation!

The core wiring for entity component systems built on trex. This macro takes a set of Components, events, and Systems, and creates a Simulation type that manages them. See the library documentation for an example of how this macro is used.

Structs

ComponentFilter

Used to filter the list of entities based on the components that are attached to them.

EventQueue

Allows for emitting events and iterating over them in the order that they were emitted. Events are immutable and queues are not flushed until the end of the frame, so multiple clients can receive events from the same queue.

Halt

Internal event used to stop the Simulation. The halt event queue will always be created.

World

Contains all entities and their components.

Traits

Component

Trait implemented by all components in order to distinguish stores of different components. this trait should never by implemented manually. Concrete components should be passed into the simulation! macro, which will implement this trait for each component.

System

Trait that must be implemented by all systems in the Simulation. The generic parameter E is the Events type generated by the simulation! macro.

Functions

calc_millis

Helper function for calculating the time in milliseconds since the last update.

next_family

Generates the next unique family. This method should never be called manually. Concrete components should be passed into the simulation! macro, which will setup the families.

Type Definitions

Entity

Used to group components.

Family

The unique family of a component.