Queries

Relevant official examples: ecs_guide.


Queries let you access components of entities.

fn check_zero_health(
    // access entities that have `Health` and `Transform` components
    // get read-only access to `Health` and mutable access to `Transform`
    // optional component: get access to `Player` if it exists
    mut query: Query<(&Health, &mut Transform, Option<&Player>)>,
) {
    // get all matching entities
    for (health, mut transform, player) in query.iter_mut() {
        eprintln!("Entity at {} has {} HP.", transform.translation, health.hp);

        // center if hp is zero
        if health.hp <= 0.0 {
            transform.translation = Vec3::ZERO;
        }

        if let Some(player) = player {
            // the current entity is the player!
            // do something special!
        }
    }
}

Get the components associated with a specific entity:

    if let Ok((health, mut transform)) = query.get_mut(entity) {
        // do something with the components
    } else {
        // the entity does not have the components from the query
    }

Get the IDs of the entities you access with your queries:

// add `Entity` to `Query` to get Entity IDs
fn query_entities(q: Query<(Entity, /* ... */)>) {
    for (e, /* ... */) in q.iter() {
        // `e` is the Entity ID of the entity we are accessing
    }
}

If you know that the query should only ever match a single entity, you can use single/single_mut (returns a Result), instead of iterating:

fn query_player(mut q: Query<(&Player, &mut Transform)>) {
    let (player, mut transform) = q.single_mut()
        .expect("There should always be exactly one player in the game!");

    // do something with the player and its transform
}

Bundles

Queries work with individual components. If you created an entity using a bundle, you need to query for the specific components from that bundle that you care about.

A common beginner mistake is to query for the bundle type!

Query Filters

Add query filters to narrow down the entities you get from the query.

Use With/Without to only get entities that have specific components.

fn debug_player_hp(
    // access the health, only for friendly players, optionally with name
    query: Query<(&Health, Option<&PlayerName>), (With<Player>, Without<Enemy>)>,
) {
    // get all matching entities
    for (health, name) in query.iter() {
        if let Some(name) = name {
            eprintln!("Player {} has {} HP.", name.0, health.hp);
        } else {
            eprintln!("Unknown player has {} HP.", health.hp);
        }
    }
}

Multiple filters can be combined:

  • in a tuple to apply all of them (AND logic)
  • using the Or<(...)> wrapper to detect any of them (OR logic).
    • (note the tuple inside)