some_bevy_tools 0.2.4

A collection of tools which can be used in the Bevy Engine.
Documentation
//! Specific physics helpers for 2D.

use bevy::prelude::*;
use bevy_rapier2d::prelude::*;

/// Contains the most required physics components.
#[derive(Bundle)]
pub struct PhysicsBundle {
    pub velocity: Velocity,
    pub collider: Collider,
    pub rigid_body: RigidBody,
    pub active_events: ActiveEvents,
    pub locked_axes: LockedAxes,
}

impl PhysicsBundle {
    /// Build a rectangle which is dynamic. Dynamic means that it is possible
    /// to apply forces and velocity.
    pub fn dynamic_rectangle(width: f32, height: f32) -> Self {
        PhysicsBundle {
            velocity: Velocity::zero(),
            collider: Collider::cuboid(width / 2.0, height / 2.0),
            rigid_body: RigidBody::Dynamic,
            active_events: ActiveEvents::COLLISION_EVENTS,
            locked_axes: LockedAxes::ROTATION_LOCKED,
        }
    }

    /// Build a rectangle which is static like a wall.
    pub fn fixed_rectangle(width: f32, height: f32) -> Self {
        PhysicsBundle {
            velocity: Velocity::zero(),
            collider: Collider::cuboid(width / 2.0, height / 2.0),
            rigid_body: RigidBody::Fixed,
            active_events: ActiveEvents::COLLISION_EVENTS,
            locked_axes: LockedAxes::ROTATION_LOCKED,
        }
    }

    /// Build a rectangle which doesn't affect entities which collides with it.
    ///
    /// This is used to place trigger to get a collision event.
    pub fn trigger(width: f32, height: f32, size_multiplier: f32) -> (Self, Sensor) {
        (
            PhysicsBundle {
                velocity: Velocity::zero(),
                collider: Collider::cuboid(
                    width / 2.0 * size_multiplier,
                    height / 2.0 * size_multiplier,
                ),
                rigid_body: RigidBody::Dynamic,
                active_events: ActiveEvents::COLLISION_EVENTS,
                locked_axes: LockedAxes::ROTATION_LOCKED,
            },
            Sensor,
        )
    }
}

/// Accelerate direciton in a two dimensions or not at all.
#[derive(Default)]
pub enum AccelerationDirection {
    #[default]
    None,
    Up,
    Down,
    Left,
    Right,
}

/// Component which specifies that an entity should accelerate.
#[derive(Component, Default)]
pub struct Acceleration {
    /// The amount of acceleration.
    pub amount: f32,
    /// Only accelerate up to this speed.
    pub max_speed: f32,
    /// In which direction to accelerate.
    pub direction: AccelerationDirection,
}
impl Acceleration {
    /// Create a new acceleration.
    pub fn new(amount: f32, max_speed: f32) -> Self {
        Acceleration {
            amount,
            max_speed,
            ..Default::default()
        }
    }
}

/// Accelerate the entities with the specified acceleration.
pub fn acceleration_controller(mut query: Query<(&mut Velocity, &Acceleration)>, time: Res<Time>) {
    for (mut velocity, acceleration) in query.iter_mut() {
        match acceleration.direction {
            AccelerationDirection::Up => {
                velocity.linvel.y += acceleration.amount * time.delta_seconds();
            }
            AccelerationDirection::Down => {
                velocity.linvel.y -= acceleration.amount * time.delta_seconds();
            }
            AccelerationDirection::Left => {
                velocity.linvel.x -= acceleration.amount * time.delta_seconds();
            }
            AccelerationDirection::Right => {
                velocity.linvel.x += acceleration.amount * time.delta_seconds();
            }
            _ => (),
        }
        velocity.linvel.x = velocity
            .linvel
            .x
            .clamp(-acceleration.max_speed, acceleration.max_speed);
        velocity.linvel.y = velocity
            .linvel
            .y
            .clamp(-acceleration.max_speed, acceleration.max_speed);
    }
}

/// Configuration for the physics 2d physics plugin.
#[derive(Default)]
pub struct Physics2DPluginConfiguration {
    /// Disable loading of the rapier plugin.
    pub no_rapier_plugin: bool,
}

/// Plugin for 2d physics.
#[derive(Default)]
pub struct Physics2DPlugin {
    /// Configuration for this plugin.
    pub configuration: Physics2DPluginConfiguration,
}
impl Plugin for Physics2DPlugin {
    fn build(&self, app: &mut App) {
        if !self.configuration.no_rapier_plugin {
            app.add_plugins(RapierPhysicsPlugin::<NoUserData>::default());
        }
        app.add_systems(Update, acceleration_controller);
    }
}