bevy_2d_box_physics 0.1.1

A 2D box-collision physics engine for use with the bevy engine
Documentation
use crate::collision::*;
use bevy::prelude::*;

/// Sensors are a bit like collisions, but instead of limiting overlapping
/// collision boxes, it just registers overlap to the SensorData and other
/// systems can use this info
#[derive(Component, Default)]
pub struct SensorBox(pub f32, pub f32);

/// A component that contains information about the state of a sensor
#[derive(Component, Default, Debug)]
pub struct SensorData {
    pub activated: bool,
}

/// Contains information about which sensors a sensor should activate with
#[derive(Component, Default)]
pub struct SensorLayers {
    pub layer_id: usize,
    pub activates_with_ids: Vec<usize>,
}

impl SensorLayers {
    fn can_activate(&self, activ_candidate: &Self) -> bool {
        self.activates_with_ids.contains(&activ_candidate.layer_id)
    }
}

/// A bundle for adding sensors
#[derive(Bundle, Default)]
pub struct SensorBundle {
    pub sensor_box: SensorBox,
    pub sensor_data: SensorData,
    pub sensor_layers: SensorLayers,
}

/// A bevy system to check for collisions with sensors (mind that sensors don't
/// need to have a rigidbody to register)
pub fn check_sensors(
    query: Query<(Entity, &Transform, &SensorBox, &SensorLayers)>,
    mut query_sensor_data: Query<(&mut SensorData,)>,
) {
    let mut entity_sensor_activated: std::collections::HashMap<Entity, bool> =
        std::collections::HashMap::new();
    let mut iter = query.iter_combinations();
    while let Some(
        [(entity1, transform1, sensor_box1, sensor_layers1), (entity2, transform2, sensor_box2, sensor_layers2)],
    ) = iter.fetch_next()
    {
        for entity in [&entity1, &entity2] {
            if entity_sensor_activated.get(entity).is_none() {
                entity_sensor_activated.insert(*entity, false);
            }
        }
        if !sensor_layers1.can_activate(sensor_layers2)
            || !sensor_layers2.can_activate(sensor_layers1)
        {
            continue;
        }
        let (pos1, pos2) = (
            transform1.translation.truncate(),
            transform2.translation.truncate(),
        );
        let is_activated = overlap(pos1.x, pos2.x, sensor_box1.0, sensor_box2.0)
            && overlap(pos1.y, pos2.y, sensor_box1.1, sensor_box2.1);
        if is_activated {
            entity_sensor_activated.insert(entity1, true);
            entity_sensor_activated.insert(entity2, true);
        }
    }
    for (entity, activated) in entity_sensor_activated {
        if let Ok(mut sensor_data) = query_sensor_data.get_mut(entity) {
            if sensor_data.0.activated != activated {
                sensor_data.0.activated = activated;
            }
        }
    }
}