From ae40f4cd7e55dd81955cd329f4d45bba040ba012 Mon Sep 17 00:00:00 2001 From: Sébastien Crozet Date: Thu, 28 Apr 2022 13:02:43 +0200 Subject: Add collision event flags --- src/dynamics/ccd/ccd_solver.rs | 16 +++++++++--- src/geometry/contact_pair.rs | 45 ++++++++++++++++++++++++++++------ src/geometry/mod.rs | 55 ++++++++++++++++++++++++++++-------------- src/geometry/narrow_phase.rs | 46 ++++++++++++++++++++++++++++------- src/pipeline/event_handler.rs | 30 ++++++++++++++++++++--- 5 files changed, 150 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/dynamics/ccd/ccd_solver.rs b/src/dynamics/ccd/ccd_solver.rs index 77a1ff7..bdde135 100644 --- a/src/dynamics/ccd/ccd_solver.rs +++ b/src/dynamics/ccd/ccd_solver.rs @@ -4,7 +4,7 @@ use crate::geometry::{ColliderParent, ColliderSet, CollisionEvent, NarrowPhase}; use crate::math::Real; use crate::parry::utils::SortedPair; use crate::pipeline::{EventHandler, QueryPipeline, QueryPipelineMode}; -use crate::prelude::ActiveEvents; +use crate::prelude::{ActiveEvents, CollisionEventFlags}; use parry::query::{DefaultQueryDispatcher, QueryDispatcher}; use parry::utils::hashmap::HashMap; use std::collections::BinaryHeap; @@ -529,8 +529,18 @@ impl CCDSolver { .contains(ActiveEvents::COLLISION_EVENTS) { // Emit one intersection-started and one intersection-stopped event. - events.handle_collision_event(CollisionEvent::Started(toi.c1, toi.c2), None); - events.handle_collision_event(CollisionEvent::Stopped(toi.c1, toi.c2, false), None); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Started(toi.c1, toi.c2, CollisionEventFlags::SENSOR), + None, + ); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Stopped(toi.c1, toi.c2, CollisionEventFlags::SENSOR), + None, + ); } } diff --git a/src/geometry/contact_pair.rs b/src/geometry/contact_pair.rs index a75d58d..551ffde 100644 --- a/src/geometry/contact_pair.rs +++ b/src/geometry/contact_pair.rs @@ -1,7 +1,8 @@ -use crate::dynamics::RigidBodyHandle; -use crate::geometry::{ColliderHandle, Contact, ContactManifold}; +use crate::dynamics::{RigidBodyHandle, RigidBodySet}; +use crate::geometry::{ColliderHandle, ColliderSet, Contact, ContactManifold}; use crate::math::{Point, Real, Vector}; use crate::pipeline::EventHandler; +use crate::prelude::CollisionEventFlags; use parry::query::ContactManifoldsWorkspace; use super::CollisionEvent; @@ -69,22 +70,36 @@ impl IntersectionPair { pub(crate) fn emit_start_event( &mut self, + bodies: &RigidBodySet, + colliders: &ColliderSet, collider1: ColliderHandle, collider2: ColliderHandle, events: &dyn EventHandler, ) { self.start_event_emited = true; - events.handle_collision_event(CollisionEvent::new(collider1, collider2, true), None); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Started(collider1, collider2, CollisionEventFlags::SENSOR), + None, + ); } pub(crate) fn emit_stop_event( &mut self, + bodies: &RigidBodySet, + colliders: &ColliderSet, collider1: ColliderHandle, collider2: ColliderHandle, events: &dyn EventHandler, ) { self.start_event_emited = false; - events.handle_collision_event(CollisionEvent::new(collider1, collider2, false), None); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Stopped(collider1, collider2, CollisionEventFlags::SENSOR), + None, + ); } } @@ -155,20 +170,34 @@ impl ContactPair { deepest } - pub(crate) fn emit_start_event(&mut self, events: &dyn EventHandler) { + pub(crate) fn emit_start_event( + &mut self, + bodies: &RigidBodySet, + colliders: &ColliderSet, + events: &dyn EventHandler, + ) { self.start_event_emited = true; events.handle_collision_event( - CollisionEvent::new(self.collider1, self.collider2, true), + bodies, + colliders, + CollisionEvent::Started(self.collider1, self.collider2, CollisionEventFlags::empty()), Some(self), ); } - pub(crate) fn emit_stop_event(&mut self, events: &dyn EventHandler) { + pub(crate) fn emit_stop_event( + &mut self, + bodies: &RigidBodySet, + colliders: &ColliderSet, + events: &dyn EventHandler, + ) { self.start_event_emited = false; events.handle_collision_event( - CollisionEvent::new(self.collider1, self.collider2, false), + bodies, + colliders, + CollisionEvent::Stopped(self.collider1, self.collider2, CollisionEventFlags::empty()), Some(self), ); } diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs index 7733ad2..d64c270 100644 --- a/src/geometry/mod.rs +++ b/src/geometry/mod.rs @@ -50,27 +50,28 @@ pub type PointProjection = parry::query::PointProjection; pub type TOI = parry::query::TOI; pub use parry::shape::SharedShape; +bitflags::bitflags! { + #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] + pub struct CollisionEventFlags: u32 { + /// Flag set if at least one of the colliders involved in the + /// collision was a sensor when the event was fired. + const SENSOR = 0b0001; + /// Flag set if a `CollisionEvent::Stopped` was fired because + /// at least one of the colliders was removed. + const REMOVED = 0b0010; + } +} + #[derive(Copy, Clone, Hash, Debug)] -/// Events occurring when two colliders start or stop being in contact (or intersecting) +/// Events occurring when two colliders start or stop colliding pub enum CollisionEvent { - /// Event occurring when two colliders start being in contact (or intersecting) - Started(ColliderHandle, ColliderHandle), - /// Event occurring when two colliders stop being in contact (or intersecting). - /// - /// The boolean is set to `true` of this event originates from at least one of - /// the colliders being removed from the `ColliderSet`. - Stopped(ColliderHandle, ColliderHandle, bool), + /// Event occurring when two colliders start colliding + Started(ColliderHandle, ColliderHandle, CollisionEventFlags), + /// Event occurring when two colliders stop colliding. + Stopped(ColliderHandle, ColliderHandle, CollisionEventFlags), } impl CollisionEvent { - pub(crate) fn new(h1: ColliderHandle, h2: ColliderHandle, start: bool) -> Self { - if start { - Self::Started(h1, h2) - } else { - Self::Stopped(h1, h2, false) - } - } - /// Is this a `Started` collision event? pub fn started(self) -> bool { matches!(self, CollisionEvent::Started(..)) @@ -84,14 +85,32 @@ impl CollisionEvent { /// The handle of the first collider involved in this collision event. pub fn collider1(self) -> ColliderHandle { match self { - Self::Started(h, _) | Self::Stopped(h, _, _) => h, + Self::Started(h, _, _) | Self::Stopped(h, _, _) => h, } } /// The handle of the second collider involved in this collision event. pub fn collider2(self) -> ColliderHandle { match self { - Self::Started(_, h) | Self::Stopped(_, h, _) => h, + Self::Started(_, h, _) | Self::Stopped(_, h, _) => h, + } + } + + /// Was at least one of the colliders involved in the collision a sensor? + pub fn sensor(self) -> bool { + match self { + Self::Started(_, _, f) | Self::Stopped(_, _, f) => { + f.contains(CollisionEventFlags::SENSOR) + } + } + } + + /// Was at least one of the colliders involved in the collision removed? + pub fn removed(self) -> bool { + match self { + Self::Started(_, _, f) | Self::Stopped(_, _, f) => { + f.contains(CollisionEventFlags::REMOVED) + } } } } diff --git a/src/geometry/narrow_phase.rs b/src/geometry/narrow_phase.rs index f4e8c58..3e7a13d 100644 --- a/src/geometry/narrow_phase.rs +++ b/src/geometry/narrow_phase.rs @@ -15,6 +15,7 @@ use crate::pipeline::{ ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext, PhysicsHooks, }; +use crate::prelude::CollisionEventFlags; use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher}; use parry::utils::IsometryOpt; use std::collections::HashMap; @@ -317,14 +318,24 @@ impl NarrowPhase { } if pair.start_event_emited { - events.handle_collision_event(CollisionEvent::Stopped(a, b, true), Some(pair)); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED), + Some(pair), + ); } } } else { // If there is no island, don’t wake-up bodies, but do send the Stopped collision event. for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) { if pair.start_event_emited { - events.handle_collision_event(CollisionEvent::Stopped(a, b, true), Some(pair)); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Stopped(a, b, CollisionEventFlags::REMOVED), + Some(pair), + ); } } } @@ -332,7 +343,16 @@ impl NarrowPhase { // Generate Stopped collision events for intersections. for (a, b, pair) in self.intersection_graph.interactions_with(contact_graph_id) { if pair.start_event_emited { - events.handle_collision_event(CollisionEvent::Stopped(a, b, true), None); + events.handle_collision_event( + bodies, + colliders, + CollisionEvent::Stopped( + a, + b, + CollisionEventFlags::REMOVED | CollisionEventFlags::SENSOR, + ), + None, + ); } } @@ -495,7 +515,13 @@ impl NarrowPhase { if (co1.flags.active_events | co2.flags.active_events) .contains(ActiveEvents::COLLISION_EVENTS) { - intersection.emit_stop_event(pair.collider1, pair.collider2, events) + intersection.emit_stop_event( + bodies, + colliders, + pair.collider1, + pair.collider2, + events, + ) } } } @@ -521,7 +547,7 @@ impl NarrowPhase { if (co1.flags.active_events | co2.flags.active_events) .contains(ActiveEvents::COLLISION_EVENTS) { - ctct.emit_stop_event(events); + ctct.emit_stop_event(bodies, colliders, events); } } } @@ -724,9 +750,11 @@ impl NarrowPhase { && had_intersection != edge.weight.intersecting { if edge.weight.intersecting { - edge.weight.emit_start_event(handle1, handle2, events); + edge.weight + .emit_start_event(bodies, colliders, handle1, handle2, events); } else { - edge.weight.emit_stop_event(handle1, handle2, events); + edge.weight + .emit_stop_event(bodies, colliders, handle1, handle2, events); } } }); @@ -928,9 +956,9 @@ impl NarrowPhase { if pair.has_any_active_contact != had_any_active_contact { if active_events.contains(ActiveEvents::COLLISION_EVENTS) { if pair.has_any_active_contact { - pair.emit_start_event(events); + pair.emit_start_event(bodies, colliders, events); } else { - pair.emit_stop_event(events); + pair.emit_stop_event(bodies, colliders, events); } } } diff --git a/src/pipeline/event_handler.rs b/src/pipeline/event_handler.rs index f08a383..f6c33ec 100644 --- a/src/pipeline/event_handler.rs +++ b/src/pipeline/event_handler.rs @@ -1,4 +1,5 @@ -use crate::geometry::{CollisionEvent, ContactPair}; +use crate::dynamics::RigidBodySet; +use crate::geometry::{ColliderSet, CollisionEvent, ContactPair}; use crossbeam::channel::Sender; bitflags::bitflags! { @@ -27,14 +28,29 @@ pub trait EventHandler: Send + Sync { /// /// # Parameters /// * `event` - The collision event. + /// * `bodies` - The set of rigid-bodies. + /// * `colliders` - The set of colliders. /// * `contact_pair` - The current state of contacts between the two colliders. This is set ot `None` /// if at least one of the collider is a sensor (in which case no contact information /// is ever computed). - fn handle_collision_event(&self, event: CollisionEvent, contact_pair: Option<&ContactPair>); + fn handle_collision_event( + &self, + bodies: &RigidBodySet, + colliders: &ColliderSet, + event: CollisionEvent, + contact_pair: Option<&ContactPair>, + ); } impl EventHandler for () { - fn handle_collision_event(&self, _event: CollisionEvent, _contact_pair: Option<&ContactPair>) {} + fn handle_collision_event( + &self, + _bodies: &RigidBodySet, + _colliders: &ColliderSet, + _event: CollisionEvent, + _contact_pair: Option<&ContactPair>, + ) { + } } /// A collision event handler that collects events into a crossbeam channel. @@ -50,7 +66,13 @@ impl ChannelEventCollector { } impl EventHandler for ChannelEventCollector { - fn handle_collision_event(&self, event: CollisionEvent, _: Option<&ContactPair>) { + fn handle_collision_event( + &self, + _bodies: &RigidBodySet, + _colliders: &ColliderSet, + event: CollisionEvent, + _: Option<&ContactPair>, + ) { let _ = self.event_sender.send(event); } } -- cgit