Relevant official examples: ecs_guide.


Entities

See here for more explanation on how storing data in the ECS works.

Conceptually, an entity represents a set of values for different components. Each component is a Rust type (struct or enum) and an entity can be used to store a value of that type.

Technically, an entity is just a simple integer ID (imagine the "row number" in a table/spreadsheet) that can be used to find related data values (in different "columns" of that table).

In Bevy, Entity is this value. It consists of two integers: the ID and the "generation" (allowing IDs to be reused, after you despawn old entities).

You can create ("spawn") new entities and destroy ("despawn") entities using Commands or exclusive World access.

fn setup(mut commands: Commands) {
    // create a new entity
    commands.spawn((
        // Initialize all your components and bundles here
        Enemy,
        Health {
            hp: 100.0,
            extra: 25.0,
        },
        AiMode::Passive,
        // ...
    ));

    // If you want to get the Entity ID, just call `.id()` after spawn
    let my_entity = commands.spawn((/* ... */)).id();

    // destroy an entity, removing all data associated with it
    commands.entity(my_entity).despawn();
}

Many of your entities might need to have the same common components. You can use Bundles to make it easier to spawn your entities.

Components

Components are the data associated with entities.

To create a new component type, simply define a Rust struct or enum, and derive the Component trait.

#[derive(Component)]
struct Health {
    hp: f32,
    extra: f32,
}

#[derive(Component)]
enum AiMode {
    Passive,
    ChasingPlayer,
}

Types must be unique – an entity can only have one component per Rust type.

Newtype Components

Use wrapper (newtype) structs to make unique components out of simpler types:

#[derive(Component)]
struct PlayerXp(u32);

#[derive(Component)]
struct PlayerName(String);

Marker Components

You can use empty structs to help you identify specific entities. These are known as "marker components". Useful with query filters.

/// Add this to all menu ui entities to help identify them
#[derive(Component)]
struct MainMenuUI;

/// Marker for hostile game units
#[derive(Component)]
struct Enemy;

/// This will be used to identify the main player entity
#[derive(Component)]
struct Player;

/// Tag all creatures that are currently friendly towards the player
#[derive(Component)]
struct Friendly;

Accessing Components

Components can be accessed from systems, using queries.

You can think of the query as the "specification" for the data you want to access. It gives you access to specific component values from entities that match the query's signature.

fn level_up_player(
    // get the relevant data. some components read-only, some mutable
    mut query_player: Query<(&PlayerName, &mut PlayerXp, &mut Health), With<Player>>,
) {
    // `single` assumes only one entity exists that matches the query
    let (name, mut xp, mut health) = query_player.single_mut();
    if xp.0 > 1000 {
        xp.0 = 0;
        health.hp = 100.0;
        health.extra += 25.0;
        info!("Player {} leveled up!", name.0);
    }
}

fn die(
    // `Entity` can be used to get the ID of things that match the query
    query_health: Query<(Entity, &Health)>,
    // we also need Commands, so we can despawn entities if we have to
    mut commands: Commands,
) {
    // we can have many such entities (enemies, player, whatever)
    // so we loop to check all of them
    for (entity_id, health) in query_health.iter() {
        if health.hp <= 0.0 {
            commands.entity(entity_id).despawn();
        }
    }
}

Adding/removing Components

You can add/remove components on existing entities, using Commands or exclusive World access.

fn make_enemies_friendly(
    query_enemy: Query<Entity, With<Enemy>>,
    mut commands: Commands,
) {
    for entity_id in query_enemy.iter() {
        commands.entity(entity_id)
            .remove::<Enemy>()
            .insert(Friendly);
    }
}

Required Components

Components can require other components. When you spawn an entity, Bevy will ensure that any additional components required by the components you provide are also added to the entity. If you do not provide a value for those components, Bevy will automatically insert a default value.

For example, the way to create a 3D camera in Bevy is to spawn an entity with the Camera3d component. Bevy will automatically make sure to also add any other necessary components, such as Camera (where Bevy stores general camera properties), Transform (transforms), and others.

These dependencies are recursive. For example, Transform requires GlobalTransform, so our camera entity will also get that automatically.

To learn what components are required by a specific component type, look for the impl Component for … under "Trait Implementations" in the API Docs.

If you want to customize the values in any of those components, you can just add them yourself.

fn setup_camera(
    mut commands: Commands,
) {
    commands.spawn((
        // Add Camera2d to pull in everything needed for a 2D camera
        Camera2d,
        // Add our own transform
        Transform::from_xyz(1.0, 2.0, 3.0),

        // By just adding the above 2 components, our entity
        // will also automatically get other things, like:
        // - `Camera`: required by `Camera2d`
        // - `GlobalTransform`: required by `Transform`
        // - and various others … (see the API docs)
        // They will be initialized with default values.
        //
        // `Camera2d` also requires `Transform`, but we provided
        // our own value for that, so Bevy will use our value
        // instead of the default.
    ));
}

You can add required components to your own component types as follows:

#[derive(Component)]
#[require(Enemy, Health, Sprite, Transform, Visibility)]
struct RegularEnemy;

#[derive(Component)]
#[require(
    Enemy,
    // init using a custom function instead of `Default`
    Health(big_boss_health),
    Sprite,
    Transform,
    Visibility,
)]
struct BigBoss;

You need to make sure that all the required components impl Default. Or alternatively, you can use a custom constructor function for initialization.

#[derive(Component, Default)]
struct Enemy;

#[derive(Component)]
struct Health(f32);

impl Default for Health {
    fn default() -> Self {
        Health(100.0)
    }
}

fn big_boss_health() -> Health {
    Health(500.0)
}

And now, with all the above, we can do:

fn spawn_enemies(
    mut commands: Commands,
) {
    commands.spawn(BigBoss);
    commands.spawn((
        RegularEnemy,
        Transform::from_xyz(10.0, 20.0, 30.0),
    ));
}