use crate::prelude::*;
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
pub struct ContactReportingPlugin;
impl Plugin for ContactReportingPlugin {
fn build(&self, app: &mut App) {
app.add_event::<Collision>()
.add_event::<CollisionStarted>()
.add_event::<CollisionEnded>();
let physics_schedule = app
.get_schedule_mut(PhysicsSchedule)
.expect("add PhysicsSchedule first");
physics_schedule.add_systems(report_contacts.in_set(PhysicsStepSet::ReportContacts));
}
}
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[derive(Event, Clone, Debug, PartialEq)]
pub struct Collision(pub Contacts);
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[derive(Event, Clone, Debug, PartialEq)]
pub struct CollisionStarted(pub Entity, pub Entity);
#[cfg_attr(feature = "2d", doc = "use bevy_xpbd_2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use bevy_xpbd_3d::prelude::*;")]
#[derive(Event, Clone, Debug, PartialEq)]
pub struct CollisionEnded(pub Entity, pub Entity);
pub fn report_contacts(
mut colliders: Query<&mut CollidingEntities>,
collisions: Res<Collisions>,
mut collision_ev_writer: EventWriter<Collision>,
mut collision_started_ev_writer: EventWriter<CollisionStarted>,
mut collision_ended_ev_writer: EventWriter<CollisionEnded>,
) {
for ((entity1, entity2), contacts) in collisions.get_internal().iter() {
if contacts.during_current_frame {
collision_ev_writer.send(Collision(contacts.clone()));
if !contacts.during_previous_frame {
collision_started_ev_writer.send(CollisionStarted(*entity1, *entity2));
if let Ok(mut colliding_entities1) = colliders.get_mut(*entity1) {
colliding_entities1.insert(*entity2);
}
if let Ok(mut colliding_entities2) = colliders.get_mut(*entity2) {
colliding_entities2.insert(*entity1);
}
}
}
if !contacts.during_current_frame && contacts.during_previous_frame {
collision_ended_ev_writer.send(CollisionEnded(*entity1, *entity2));
if let Ok(mut colliding_entities1) = colliders.get_mut(*entity1) {
colliding_entities1.remove(entity2);
}
if let Ok(mut colliding_entities2) = colliders.get_mut(*entity2) {
colliding_entities2.remove(entity1);
}
}
}
}