use crate::dynamics::RigidBodySet; use crate::geometry::{ColliderSet, CollisionEvent, ContactForceEvent, ContactPair}; use crate::math::Real; use crossbeam::channel::Sender; bitflags::bitflags! { #[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] /// Flags affecting the events generated for this collider. pub struct ActiveEvents: u32 { /// If set, Rapier will call `EventHandler::handle_collision_event` /// whenever relevant for this collider. const COLLISION_EVENTS = 0b0001; /// If set, Rapier will call `EventHandler::handle_contact_force_event` /// whenever relevant for this collider. const CONTACT_FORCE_EVENTS = 0b0010; } } impl Default for ActiveEvents { fn default() -> Self { ActiveEvents::empty() } } /// Trait implemented by structures responsible for handling events generated by the physics engine. /// /// Implementors of this trait will typically collect these events for future processing. pub trait EventHandler: Send + Sync { /// Handle a collision event. /// /// A collision event is emitted when the state of intersection between two colliders changes. /// At least one of the involved colliders must have the `ActiveEvents::COLLISION_EVENTS` flag /// set. /// /// # 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, bodies: &RigidBodySet, colliders: &ColliderSet, event: CollisionEvent, contact_pair: Option<&ContactPair>, ); /// Handle a force event. /// /// A force event is generated whenever the total force magnitude applied between two /// colliders is `> Collider::contact_force_event_threshold` value of any of these /// colliders with the `ActiveEvents::CONTACT_FORCE_EVENTS` flag set. /// /// The "total force magnitude" here means "the sum of the magnitudes of the forces applied at /// all the contact points in a contact pair". Therefore, if the contact pair involves two /// forces `{0.0, 1.0, 0.0}` and `{0.0, -1.0, 0.0}`, then the total force magnitude tested /// against the `contact_force_event_threshold` is `2.0` even if the sum of these forces is actually the /// zero vector. fn handle_contact_force_event( &self, dt: Real, bodies: &RigidBodySet, colliders: &ColliderSet, contact_pair: &ContactPair, total_force_magnitude: Real, ); } impl EventHandler for () { fn handle_collision_event( &self, _bodies: &RigidBodySet, _colliders: &ColliderSet, _event: CollisionEvent, _contact_pair: Option<&ContactPair>, ) { } fn handle_contact_force_event( &self, _dt: Real, _bodies: &RigidBodySet, _colliders: &ColliderSet, _contact_pair: &ContactPair, _total_force_magnitude: Real, ) { } } /// A collision event handler that collects events into a crossbeam channel. pub struct ChannelEventCollector { collision_event_sender: Sender, contact_force_event_sender: Sender, } impl ChannelEventCollector { /// Initialize a new collision event handler from crossbeam channel senders. pub fn new( collision_event_sender: Sender, contact_force_event_sender: Sender, ) -> Self { Self { collision_event_sender, contact_force_event_sender, } } } impl EventHandler for ChannelEventCollector { fn handle_collision_event( &self, _bodies: &RigidBodySet, _colliders: &ColliderSet, event: CollisionEvent, _: Option<&ContactPair>, ) { let _ = self.collision_event_sender.send(event); } fn handle_contact_force_event( &self, dt: Real, _bodies: &RigidBodySet, _colliders: &ColliderSet, contact_pair: &ContactPair, total_force_magnitude: Real, ) { let result = ContactForceEvent::from_contact_pair(dt, contact_pair, total_force_magnitude); let _ = self.contact_force_event_sender.send(result); } }