Crate evenio

Crate evenio 

Source
Expand description

§Evenio

evenio is an archetype-based Entity Component System framework for building event-driven programs. It aims to have a small but maximally expressive set of features that are easy and efficient to use.

§Features

  • In addition to the usual Entities, Components, and Systems, evenio introduces events as a first-class citizen. Rather than restricting systems to run once every frame/update in a fixed order, systems are generalized as event handlers. The control flow of the entire program is then defined by the flow of events between handlers.
  • Structural changes to the world (such as entity despawning, component additions/removals, etc.) are mediated by events, allowing handlers to hook into their occurrence.
  • Targeted events enable handlers to efficiently filter events based on queries.
  • Component types, event types, and handlers are identified with generational indices, allowing them to be added and removed dynamically.
  • Execute queries in parallel with Rayon.
  • World data has no Send or Sync requirements.
  • no_std support.

For a full step-by-step introduction, please read the tutorial book 📚.

§Example

Here’s how we might make a simple game loop in evenio:

use evenio::prelude::*;

// Define position and velocity components.
#[derive(Component)]
struct Position {
    x: f32,
    y: f32,
}

#[derive(Component)]
struct Velocity {
    x: f32,
    y: f32,
}

// Events can carry data, but for this example we only need a unit struct.
#[derive(GlobalEvent)]
struct Tick;

pub fn main() {
    // Create a new `World` to store all our data.
    let mut world = World::new();

    // Spawn a new entity and add the `Position` and `Velocity` components to it.
    // We'll store the entity's ID in a variable for later use.
    let e = world.spawn();
    world.insert(e, Position { x: 0.0, y: 0.0 });
    world.insert(e, Velocity { x: 1.0, y: 0.4 });

    // Add our event handler to the world.
    world.add_handler(update_positions);

    // Run our fake "game loop" by sending the `Tick` event every update.
    for _ in 0..50 {
        world.send(Tick);
    }

    // Get the `Position` component from the entity we added earlier.
    let pos = world.get::<Position>(e).unwrap();

    println!("Final position of the entity: ({}, {})", pos.x, pos.y);
}

// The `Receiver<Tick>` parameter tells our handler to listen for the `Tick` event.
fn update_positions(_: Receiver<Tick>, entities: Fetcher<(&mut Position, &Velocity)>) {
    // Loop over all entities with both the `Position` and `Velocity` components, and update their positions.
    for (pos, vel) in entities {
        pos.x += vel.x;
        pos.y += vel.y;
    }
}

§Feature Flags

  • std (enabled by default): Enables support for the standard library. Without this, evenio depends only on core and alloc.
  • rayon: Adds parallel iterator support for Fetcher. Uses the Rayon library.

Re-exports§

pub use rayon;rayon

Modules§

access
Data access checking.
archetype
Archetype and related items.
component
Types for working with Components.
drop
Drop utilities.
entity
Entity related items.
event
Types for sending and receiving Events.
fetch
Accessing components on entities.
handler
Event handlers
mutability
Mutability and related marker types.
prelude
Re-exports of the most commonly used items in the library.
query
Type-level DSL for retrieving data from entities.
tutorial
Why ECS?
world
Defines the World and related APIs.