Queries

Relevant official examples: ecs_guide.


Queries let you access components of entities.

Use the Query system parameter, where you can specify the data you want to access, and optionally additional filters for selecting entities.

Think of the types you put in your Query as a "specification" for selecting what entities you want to access. Queries will match only those entities in the ECS World that fit your specification. You are then able to access the relevant data from individual such entities (using an Entity ID), or iterate to access all entities that qualify.

The first type parameter for a query is the data you want to access. Use & for shared/readonly access and &mut for exclusive/mutable access. Use Option if the component is not required (you want to find entities with or without that component. If you want multiple components, put them in a tuple.

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!
        }
    }
}

The above example used iteration to access all entities that the query could find.

To access the components from specific entity only:

    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
    }

If you want to know the entity IDs of the entities you are accessing, you can put the special Entity type in your query. This is useful together with iteration, so you can identify the entities that the query found:

// 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 is expected to only ever match a single entity, you can use single/single_mut (panic on error) or get_single/get_single_mut (return Result). These methods ensure that there exists exactly one candidate entity that can match your query, and will produce an error otherwise.

fn query_player(mut q: Query<(&Player, &mut Transform)>) {
    let (player, mut transform) = q.single_mut();

    // 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.

This is done using the second (optional) generic type parameter of the Query type.

Note the syntax of the query: first you specify the data you want to access (using a tuple to access multiple things), and then you add any additional filters (can also be a tuple, to add multiple).

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

fn debug_player_hp(
    // access the health (and optionally the PlayerName, if present), only for friendly players
    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);
        }
    }
}

This is useful if you don't actually care about the data stored inside these components, but you want to make sure that your query only looks for entities that have (or not have) them. If you want the data, then put the component in the first part of the query (as shown previously), instead of using a filter.

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)