|
use bevy::{ prelude::*, utils::HashSet }; |
|
use bevy_rapier2d::{ geometry::{ ActiveEvents, Collider, Sensor }, pipeline::CollisionEvent }; |
|
|
|
use crate::plugins::rapier_utils::reciprocal_collisions; |
|
|
|
#[derive(Clone, Default, Component)] |
|
pub struct GroundDetection { |
|
pub on_ground: bool, |
|
} |
|
|
|
#[derive(Component)] |
|
pub struct GroundSensor { |
|
pub ground_detection_entity: Entity, |
|
pub intersecting_ground_entities: HashSet<Entity>, |
|
} |
|
|
|
pub fn spawn_ground_sensor( |
|
mut commands: Commands, |
|
detect_ground_for: Query<(Entity, &Collider), Added<GroundDetection>> |
|
) { |
|
for (entity, shape) in &detect_ground_for { |
|
if let Some(cuboid) = shape.as_cuboid() { |
|
let Vec2 { x: half_extents_x, y: half_extents_y } = cuboid.half_extents(); |
|
|
|
let detector_shape = Collider::cuboid(half_extents_x / 2.0, 2.0); |
|
|
|
let sensor_translation = Vec3::new(0.0, -half_extents_y, 0.0); |
|
|
|
commands.entity(entity).with_children(|builder| { |
|
builder |
|
.spawn_empty() |
|
.insert(Name::new("ground_sensor")) |
|
.insert(ActiveEvents::COLLISION_EVENTS) |
|
.insert(detector_shape) |
|
.insert(Sensor) |
|
.insert(Transform::from_translation(sensor_translation)) |
|
.insert(GlobalTransform::default()) |
|
.insert(GroundSensor { |
|
ground_detection_entity: entity, |
|
intersecting_ground_entities: HashSet::new(), |
|
}); |
|
}); |
|
} |
|
} |
|
} |
|
|
|
pub fn ground_detection( |
|
mut ground_sensors: Query<&mut GroundSensor>, |
|
mut collisions: EventReader<CollisionEvent>, |
|
collidables: Query<Entity, (With<Collider>, Without<Sensor>)> |
|
) { |
|
reciprocal_collisions(&mut collisions, move |e1, e2, _, start| { |
|
if let (true, Ok(mut sensor)) = (collidables.contains(*e1), ground_sensors.get_mut(*e2)) { |
|
if start { |
|
sensor.intersecting_ground_entities.insert(*e1); |
|
} else { |
|
sensor.intersecting_ground_entities.remove(e1); |
|
} |
|
true |
|
} else { |
|
false |
|
} |
|
}); |
|
} |
|
|
|
pub fn update_on_ground( |
|
mut ground_detectors: Query<&mut GroundDetection>, |
|
ground_sensors: Query<&GroundSensor, Changed<GroundSensor>> |
|
) { |
|
for sensor in &ground_sensors { |
|
if let Ok(mut ground_detection) = ground_detectors.get_mut(sensor.ground_detection_entity) { |
|
ground_detection.on_ground = !sensor.intersecting_ground_entities.is_empty(); |
|
} |
|
} |
|
} |
|
|