Expand description

Worlds store collections of entities. An entity is a collection of components, identified by a unique Entity ID.

Creating a world

let mut world = World::default();

World::new() can be used to construct a new world with custom options.

Inserting entities

Entities can be inserted via either push (for a single entity) or extend (for a collection of entities with the same component types). The world will create a unique ID for each entity upon insertion that you can use to refer to that entity later.

// a component is any type that is 'static, sized, send and sync
#[derive(Clone, Copy, Debug, PartialEq)]
struct Position {
    x: f32,
    y: f32,
}

#[derive(Clone, Copy, Debug, PartialEq)]
struct Velocity {
    dx: f32,
    dy: f32,
}

// push a component tuple into the world to create an entity
let entity: Entity = world.push((Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }));

// or extend via an IntoIterator of tuples to add many at once
// this is faster than individual pushes
let entities: &[Entity] = world.extend(vec![
    (Position { x: 0.0, y: 0.0 }, Velocity { dx: 0.0, dy: 0.0 }),
    (Position { x: 1.0, y: 1.0 }, Velocity { dx: 0.0, dy: 0.0 }),
    (Position { x: 2.0, y: 2.0 }, Velocity { dx: 0.0, dy: 0.0 }),
]);

If your data is already organized as such, you can alternatively insert entities as a strucure-of-arrays.

let mut world = World::default();
let _entities = world.extend(
    (
        vec![1usize, 2usize, 3usize],
        vec![false, true, false],
        vec![5.3f32, 5.3f32, 5.2f32],
    )
        .into_soa(),
);

SoA inserts require all vectors to have the same length. These inserts are faster than inserting via an iterator of tuples.

Modifying entities

Components can be added or removed from an existing entity via the Entry API.

// entries return `None` if the entity does not exist
if let Some(mut entry) = world.entry(entity) {
    // add an extra component
    entry.add_component(12f32);

    // remove a component
    entry.remove_component::<usize>();
}

Note that it is significantly faster to create an entity with its initial set of components via push or extend than it is to add the components one-by-one after creating the entity.

Accessing components

The fastest way to access a large number of entities’ components is via queries.

The entry API also allows access to an individual entity’s components.

// entries return `None` if the entity does not exist
if let Some(mut entry) = world.entry(entity) {
    // access information about the entity's archetype
    println!(
        "{:?} has {:?}",
        entity,
        entry.archetype().layout().component_types()
    );

    // access the entity's components, returns `None` if the entity does not have the component
    assert_eq!(entry.get_component::<f32>().unwrap(), &12f32);
}

Events

Notifications about archetype creation and entity insertion/removal from an archetype can be sent to an EventSender by subscribing to the world. A layout filter specifies which archetypes the subscriber is interested in.

// subscribe to events involving entities with a `Position` with a
// crossbeam channel.
let (tx, rx) = crossbeam_channel::unbounded::<legion::world::Event>();
world.subscribe(tx, component::<Position>());

World splitting

World splitting allows mutable access to a world via multiple entries or queries at the same time, provided that their component accesses do not conflict with one another.

let mut world = World::default();
let entity = world.push((A, B, C));
let (mut left, mut right) = world.split::<(Read<A>, Write<B>)>();

// left only has permission to read A and read/write B.
let b: &mut B = left
    .entry_mut(entity)
    .unwrap()
    .get_component_mut::<B>()
    .unwrap();

// right can access anything _but_ writes to A and read/write to B.
let a: &A = right
    .entry_ref(entity)
    .unwrap()
    .get_component::<A>()
    .unwrap();
let c: &C = right
    .entry_ref(entity)
    .unwrap()
    .get_component::<C>()
    .unwrap();

Structs

An iterator which yields new entity IDs.

A Merger which clones entities from the source world into the destination, potentially performing data transformations in the process.

An opaque identifier for an entity.

The storage location of an entity’s data.

Provides safe read and write access to an entity’s components, and the ability to modify the entity.

Provides safe read and write access to an entity’s components.

Provides safe read-only access to an entity’s components.

A map of entity IDs to their storage locations.

Describes read and write access to resources.

Provides access to the archetypes and entity components contained within a world.

Provides access to a subset of the entities of a World.

A container of entities.

Unique identifier for a World.

Describes configuration options for the creation of a new World.

Enums

Describes which archetypes are available for access.

Describes which components are available for access.

An error type which describes why an attempt to retrieve a component failed.

Error type representing a failure to access entity data.

Describes how a merger wishes Entity references inside cloned components to be rewritten.

Events emitted by a world to subscribers. See World.subscribe(Sender, EntityFilter).

Traits

The EntityStore trait abstracts access to entity data as required by queries for both World and SubWorld

Describes a type which can send entity events.

Describes how to merge two Worlds.

Type Definitions

A hasher optimized for entity IDs.