Basics

At its simplest form, a query is composed of a Fetch which specify the group of components to select. The query will visit the subset of entities in the world which have the specified components, and return their values.

In order to execute a query, it has borrow the relevant data from the world. This returns a QueryBorrow which can then be iterated.

#![allow(unused)]

fn main() {
        let mut query = Query::new(name());

        for name in &mut query.borrow(&world) {
            tracing::info!("Entity: {name:?}");
        }

}

A tuple can be used which will yield the entities with all the specified components, such as all entities with a name, position, and health; which excludes all the pretty rocks.

#![allow(unused)]

fn main() {
        let mut query = Query::new((name(), position(), health()));

        for (name, pos, health) in &mut query.borrow(&world) {
            tracing::info!("Entity: {name:?} pos: {pos}, health: {health}");
        }

}

Mutation

.as_mut will transform a component into yielding mutable references.

#![allow(unused)]

fn main() {
        fn lightning_strike(world: &World, rng: &mut StdRng) {
            let mut query = Query::new(health().as_mut());
            for h in &mut query.borrow(world) {
                // &mut f32
                *h -= rng.gen_range(10.0..20.0);
            }
        }

        lightning_strike(&world, &mut rng);

}

Optional

.opt makes a part of the fetch optional. This can be applied to a single component, or to the tuple or nested tuples as a whole.

In addition, .opt_or, and .opt_or_default allows specifying a fallback if the entity does not have the component.

#![allow(unused)]

fn main() {
        let mut query = Query::new((name(), position(), health().opt()));

        (&mut query.borrow(&world)).into_iter().for_each(
            |(name, pos, health): (&String, &Vec3, Option<&f32>)| {
                tracing::info!("Entity: {name:?} pos: {pos}, health: {health:?}");
            },
        );

}