Crate flax

source ·
Expand description

Flax is a performant and easy to use Entity Component System.

The world is organized by simple identifiers known as an Entity, which can have any number of components attached to them.

Systems operate and iterate upon entities and their attached components and provide the application logic.

Features

Consider reading the User Guide

Live Demo

See a live demo of asteroids using wasm here.

Example Usage

  // Declare static components
  use flax::*;
  component! {
    health: f32,
    regen: f32,
    pos: (f32, f32),
    player: (),
    items: Vec<String>,
  }

  let mut world = World::new();

  // Spawn an entity
  let p = EntityBuilder::new()
      .set(health(), 50.0)
      .tag(player())
      .set(pos(), (0.0, 0.0))
      .set(regen(), 1.0)
      .set_default(items())
      .spawn(&mut world);

  let mut query = Query::new((health().as_mut(), regen()));

  // Apply health regen for all match entites
  for (health, regen) in &mut query.borrow(&world) {
      *health = (*health + regen).min(100.0);
  }

Systems

Queries with logic can be abstracted into a system, and multiple systems can be collected into a schedule.

let regen_system = System::builder()
    .with(Query::new((health().as_mut(), regen())))
    .for_each(|(health, regen)| {
        *health = (*health + regen).min(100.0);
    })
    .boxed();

let despawn_system = System::builder()
    .with(Query::new(entity_ids()).filter(health().le(0.0)))
    .write::<CommandBuffer>()
    .build(|mut q: QueryBorrow<EntityIds, _>, cmd: &mut CommandBuffer| {
        for id in &mut q {
            cmd.despawn(id);
        }
    })
    .boxed();

let mut schedule = Schedule::from([regen_system, despawn_system]);

schedule.execute_par(&mut world)?;

Relations

Flax provides first class many-many relations between entities, which is useful for tree scene hierarchies, graphs, and physics joints between entities.

Relations can be both state-less or have associated data, like spring or joint strengths.

Relations are cache friendly and querying children of does not require random access. In addition, relations are cleaned up on despawns and are stable during serialization, even if the entity ids migrate due to collisions.

See the guide for more details.

component! {
    child_of(parent): () => [Debug],
}

let mut world = World::new();

let parent = Entity::builder()
    .set(name(), "Parent".into())
    .spawn(&mut world);

let child1 = Entity::builder()
    .set(name(), "Child1".into())
    .set_default(child_of(parent))
    .spawn(&mut world);

Comparison to other ECS

Compared to other ecs implementations, a component is simply another Entity identifier to which data is attached. This means the same “type” can be added to an entity multiple times.

A limitation of existing implementations such as specs, planck, or hecs is that newtype wrappers need to be created to allow components of the same inner type to coexist.

This leads to having to forward all trait implementations trough e.g derive-more or dereferencing the newtypes during usage.

By making components separate from the type the components can work together without deref or newtype construction.

component! {
    velocity: Vec3,
    position: Vec3,
}

let vel = world.get(entity, velocity())?;
let mut pos = world.get_mut(entity, position())?;
let dt = 0.1;

*pos += *vel * dt;

On a further note, since the components have to be declared beforehand (not always true, more on that later), it limits the amount of types which can be inserted as components. This fixes subtle bugs which come by having the type dictate the component, such as inserting an Arc<Type> instead of just Type, which leads to subsequent systems not finding the Type on the entity.

Having statically declared componenents makes the rust type system disallow these cases and catches these bugs earlier.

Motivation

During development of a game in school I used the hecs ECS. It is an awesome library, and the author Ralith has been wonderful in accepting contributions and inquiries.

Despite this, I often made subtle bugs with similar types. The game engine was cluttered with gigantic newtypes for Velocity, Position with many deref coercions in order to coexist.

Unsafe

This library makes use of unsafe for type erasure and the allocation in storage of ComponentBuffers and Archetypes.

Re-exports

pub use archetype::ArchetypeId;
pub use archetype::ComponentInfo;
pub use commands::CommandBuffer;
pub use entity::entity_ids;
pub use entity::Entity;
pub use error::Error;
pub use fetch::EntityIds;
pub use fetch::Fetch;
pub use fetch::FetchItem;
pub use filter::All;
pub use filter::And;
pub use filter::Filter;
pub use filter::Or;
pub use filter::StaticFilter;
pub use filter::With;
pub use filter::Without;
pub use components::*;
pub use schedule::*;
pub use visitors::*;

Modules

Structured component storage
Provides a buffer for holding multiple types simultaneously
Contains a commandbuffer
This module contains standard components that different libraries can agree on, though they don’t have to.
Provides entity identifiers
Defines the single error type and result alias
Subscribe to changes in the world
Traits for fetching multiple component values simultaneously
Filter items yielded queries
System execution
Provides a debug visitor

Macros

Declarative component generation

Structs

Describes an access for a system, allowing for dependency resolution and multithreading
Human friendly system access
Iterates over a chunk of entities, specified by a predicate. In essence, this is the unflattened version of crate::QueryIter.
Allows batch spawning many entities with the same components
An iterator which yield disjoint continuous slices for each mathed archetype and filter predicate.
A type erased system
An iterator over a single archetype which returns chunks. The chunk size is determined by the largest continuous matched entities for filters.
Defines a strongly typed component
A unique component identifier Is not stable between executions, and should as such not be used for execution.
Entity(Query)Borrow
Incrementally build a single entity which allows for more efficient insertion into the world.
Debug formats the specified entities, Created using World::format_entities
Similar to Query, except optimized to only fetch a single entity.
Provides a query and a borrow of the world during system execution
Borrow all the components of an entity at once.
Borrow all the components of an entity at once.
Holds the migrated components
Mutable component fetch See crate::Component::as_mut
Name metadata
Transform a fetch into a optional fetch
Transform a fetch into a optional fetch
Execute a function for each item in the query in parallel batches
Represents a query and state for a given world. The archetypes to visit is cached in the query which means it is more performant to reuse the query than creating a new one.
A lazily prepared query which borrows and hands out chunk iterators for each archetype matched.
Provides a query and a borrow of the world during system execution
The query iterator
Returns a list of relations of a specified type
Iterates reserved entity ids.
A resource that can be shared between systems The difference between this and an Arc<Mutex<_>> is that this will be taken into consideration when multithreading in the schedule, and will as such not require locks.
Holds the data and an inner system satisfying all dependencies
A system builder which allows incrementally adding data to a system function.
Holds external context for system execution. Contains the world and a commandbuffer
Holds the entities and components of the ECS.
Debug formats the world with the given filter. Created using World::format_debug

Enums

Describes a kind of access
Represents a change for a slice of entities for a specific component

Traits

Allows dereferencing AtomicRef<T> to &T and similar “lock” types in a safe manner.
A filter which compare a component before yielding an item from the query
Trait alias for a ’static + Send + Sync type which can be used as a component.
Extension trait for crate::Fetch
Additional data that can attach itself to a component
Relation helper trait
Describe an access to the world in ters of shared and unique accesses
Describes a type which can fetch assocated Data from the system context and provide it to the system.
A callable function

Functions

Query all relations of the specified kind

Type Definitions

Type alias for a function which instantiates a component
Type alias for a function which instantiates a relation with the specified object

Derive Macros