Basic Physics

It wouldn't be a platformer if you can't fall. Let's add some "gravity" to the game.

We'll compute an Axis Aligned Bounding Box (or AABB) for the player and the ground, and check for intersections. If there's one, then the player is on the ground. Otherwise, the player is in the air, then move its position down to simulate falling.

#![allow(unused)]
fn main() {
extern crate bevy;
#[derive(Component)]
struct Player;
#[derive(Component)]
struct Ground;
use bevy::{
    math::bounding::{Aabb2d, IntersectsVolume},
    prelude::*,
};
fn gravity(
    mut player: Query<&mut Transform, With<Player>>,
    ground: Query<&Transform, (Without<Player>, With<Ground>)>,
) {
    let mut is_on_ground = false;
    let mut player_transform = player.single_mut();

    let player_aabb = Aabb2d::new(
        Vec2::new(
            player_transform.translation.x,
            player_transform.translation.y,
        ),
        Vec2::new(
            128.0 * player_transform.scale.x,
            256.0 * player_transform.scale.y,
        ) / 2.0,
    );

    for ground_transform in &ground {
        let ground_aabb = Aabb2d::new(
            Vec2::new(
                ground_transform.translation.x,
                ground_transform.translation.y,
            ),
            Vec2::new(
                128.0 * ground_transform.scale.x,
                128.0 * ground_transform.scale.y,
            ) / 2.0,
        );

        if ground_aabb.intersects(&player_aabb) {
            is_on_ground = true;
        }
    }
    if !is_on_ground {
        player_transform.translation.y -= 10.0;
    }
}
}

Don't forget to add the new gravity system to the game_plugin, on FixedUpdate in the GameState::Game state.

Disjoint Queries

Accessing the Transform component both mutably and immutably in the same system is not possible, unless we can prove the two queries are disjoint. The filters do this.