Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Queries: Systems, Twice

Our systems can work just great like normal functions as we've already seen, but what if you actually want to do something with an entity after you spawn it? That's where you need to use a Query. A Query takes a list of components and gives you back all entities who have those components. This is also where you specify how you want to access each component of that entity. Do you want to change something? Then it needs to be Mut<T>. If you only want to reference the component, then Ref<T> is the way to go. If you want to mutate any of the components of your Query, then you must also make the Query mut.

For right now we are only spawning one entity. That makes it very easy to query.

srclib.rs
use engine::prelude::*;
mod ffi;

#[system_once]
fn spawn_player() {
    let transform = &Transform {
        position: Vec2::new(110., 0.),
        scale: Vec2::splat(3.0),
        ..Default::default()
    };
    let color = &Color::ORANGE;
    let circle_render = &CircleRender {
        num_sides: 20,
        ..Default::default()
    };
    Engine::spawn(bundle!(transform, color, circle_render));
}

#[system]
fn move_player(mut player: Query<Mut<Transform>>) {
    player.for_each(|mut transform| {
        if (transform.position.x >= 100.) {
            transform.position.y += 5.0;
        } else if (transform.position.x <= -100.) {
            transform.position.y -= 5.0;
        }

        if (transform.position.y >= 100.) {
            transform.position.x -= 5.0;
        } else if (transform.position.y <= -100.) {
            transform.position.x += 5.0;
        }
    });
}

Here you can see we've added a new system, queried our player, and we get this beautiful result:

whirlycircle

Now, using what we know, I want to add an enemy to the game! Let's add a system in, maybe change up the colors to differentiate them...

srclib.rs
use engine::prelude::*;
mod ffi;

#[system_once]
fn spawn_player() {
    let transform = &Transform {
        position: Vec2::new(110., 0.),
        scale: Vec2::splat(3.0),
        ..Default::default()
    };
    let color = &Color::new(0.96, 0.65, 0.14, 0.9);
    let circle_render = &CircleRender {
        num_sides: 20,
        ..Default::default()
    };
    Engine::spawn(bundle!(transform, color, circle_render));
}

#[system_once]
fn spawn_enemy() {
    let transform = &Transform {
        position: Vec2::new(-110., 0.),
        scale: Vec2::splat(3.0),
        ..Default::default()
    };
    let color = &Color::new(0.2, 0.2, 0.9, 0.9);
    let circle_render = &CircleRender {
        num_sides: 20,
        ..Default::default()
    };
    Engine::spawn(bundle!(transform, color, circle_render));
}

#[system]
fn move_player(mut player: Query<Mut<Transform>>) {
    player.for_each(|mut transform| {
        if (transform.position.x >= 100.) {
            transform.position.y += 5.0;
        } else if (transform.position.x <= -100.) {
            transform.position.y -= 5.0;
        }

        if (transform.position.y >= 100.) {
            transform.position.x -= 5.0;
        } else if (transform.position.y <= -100.) {
            transform.position.x += 5.0;
        }
    });
}

whirlycircle

Oh my gosh! What a surprise! They're both moving?

Who could have predicted this?

Queries don't care that you think of them as different things, or call for a player, they'll grab every entity that has the required components. No, if we want to differentiate two very similar entities from each other, we're going to need to learn how to make our own custom components.