Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ContactReportingPlugin #182

Merged
merged 7 commits into from
Oct 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions src/components/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@ impl RigidBody {
/// collisions or other constraints, or when gravity changes, or when the body's
/// position, rotation, velocity, or external forces are modified.
///
/// Note that sleeping can cause unrealistic behaviour in some cases.
/// For example, removing the floor under sleeping bodies can leave them floating in the air.
/// Sleeping can be disabled for specific entities with the [`SleepingDisabled`] component,
/// or for all entities by setting the [`SleepingThreshold`] to a negative value.
#[derive(Reflect, Clone, Copy, Component, Debug, Default, PartialEq, Eq, From)]
Expand Down
9 changes: 7 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -518,8 +518,9 @@ pub enum PhysicsSet {
/// 3. Solve positional and angular constraints
/// 4. Update velocities
/// 5. Solve velocity constraints (dynamic friction and restitution)
/// 3. Sleeping
/// 4. Spatial queries
/// 3. Report contacts (send collision events)
/// 4. Sleeping
/// 5. Spatial queries
#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum PhysicsStepSet {
/// Responsible for collecting pairs of potentially colliding entities into [`BroadCollisionPairs`] using
Expand All @@ -531,6 +532,10 @@ pub enum PhysicsStepSet {
///
/// See [`SubstepSet`] and [`SubstepSchedule`].
Substeps,
/// Responsible for sending collision events and updating [`CollidingEntities`].
///
/// See [`ContactReportingPlugin`].
ReportContacts,
/// Responsible for controlling when bodies should be deactivated and marked as [`Sleeping`].
///
/// See [`SleepingPlugin`].
Expand Down
79 changes: 79 additions & 0 deletions src/plugins/contact_reporting.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
//! Sends collision events and updates [`CollidingEntities`].
//!
//! See [`ContactReportingPlugin`].

use crate::prelude::*;

/// Sends collision events and updates [`CollidingEntities`].
///
/// The following collision events are sent each frame in [`PhysicsStepSet::ReportContacts`]:
///
/// - [`Collision`]
/// - [`CollisionStarted`]
/// - [`CollisionEnded`]
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));
}
}

/// A [collision event](Collider#collision-events) that is sent for each contact pair during the narrow phase.
#[derive(Event, Clone, Debug, PartialEq)]
pub struct Collision(pub Contacts);

/// A [collision event](Collider#collision-events) that is sent when two entities start colliding.
#[derive(Event, Clone, Debug, PartialEq)]
pub struct CollisionStarted(pub Entity, pub Entity);

/// A [collision event](Collider#collision-events) that is sent when two entities stop colliding.
#[derive(Event, Clone, Debug, PartialEq)]
pub struct CollisionEnded(pub Entity, pub Entity);

/// Sends collision events and updates [`CollidingEntities`].
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()));

// Collision started
if contacts.during_current_frame && !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);
}
}
}

// Collision ended
if !contacts.during_current_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);
}
}
}
}
6 changes: 5 additions & 1 deletion src/plugins/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
//! - [`SubstepSchedule`] and [`SubstepSet`]

pub mod broad_phase;
pub mod contact_reporting;
#[cfg(feature = "debug-plugin")]
pub mod debug;
pub mod integrator;
Expand All @@ -33,10 +34,11 @@ pub mod spatial_query;
pub mod sync;

pub use broad_phase::BroadPhasePlugin;
pub use contact_reporting::*;
#[cfg(feature = "debug-plugin")]
pub use debug::*;
pub use integrator::IntegratorPlugin;
pub use narrow_phase::*;
pub use narrow_phase::{contact_data::*, contact_query::*, NarrowPhaseConfig, NarrowPhasePlugin};
pub use prepare::PreparePlugin;
pub use setup::*;
pub use sleeping::SleepingPlugin;
Expand All @@ -59,6 +61,7 @@ use bevy::prelude::*;
/// [AABB](ColliderAabb) intersection checks.
/// - [`IntegratorPlugin`]: Integrates Newton's 2nd law of motion, applying forces and moving entities according to their velocities.
/// - [`NarrowPhasePlugin`]: Computes contacts between entities and sends collision events.
/// - [`ContactReportingPlugin`]: Sends collision events and updates [`CollidingEntities`].
/// - [`SolverPlugin`]: Solves positional and angular [constraints], updates velocities and solves velocity constraints
/// (dynamic [friction](Friction) and [restitution](Restitution)).
/// - [`SleepingPlugin`]: Controls when bodies should be deactivated and marked as [`Sleeping`] to improve performance.
Expand Down Expand Up @@ -197,6 +200,7 @@ impl PluginGroup for PhysicsPlugins {
.add(BroadPhasePlugin)
.add(IntegratorPlugin)
.add(NarrowPhasePlugin)
.add(ContactReportingPlugin)
.add(SolverPlugin)
.add(SleepingPlugin)
.add(SpatialQueryPlugin::new(self.schedule.dyn_clone()))
Expand Down
Loading