Add collision event flags
This commit is contained in:
@@ -4,7 +4,7 @@ use crate::geometry::{ColliderParent, ColliderSet, CollisionEvent, NarrowPhase};
|
|||||||
use crate::math::Real;
|
use crate::math::Real;
|
||||||
use crate::parry::utils::SortedPair;
|
use crate::parry::utils::SortedPair;
|
||||||
use crate::pipeline::{EventHandler, QueryPipeline, QueryPipelineMode};
|
use crate::pipeline::{EventHandler, QueryPipeline, QueryPipelineMode};
|
||||||
use crate::prelude::ActiveEvents;
|
use crate::prelude::{ActiveEvents, CollisionEventFlags};
|
||||||
use parry::query::{DefaultQueryDispatcher, QueryDispatcher};
|
use parry::query::{DefaultQueryDispatcher, QueryDispatcher};
|
||||||
use parry::utils::hashmap::HashMap;
|
use parry::utils::hashmap::HashMap;
|
||||||
use std::collections::BinaryHeap;
|
use std::collections::BinaryHeap;
|
||||||
@@ -529,8 +529,18 @@ impl CCDSolver {
|
|||||||
.contains(ActiveEvents::COLLISION_EVENTS)
|
.contains(ActiveEvents::COLLISION_EVENTS)
|
||||||
{
|
{
|
||||||
// Emit one intersection-started and one intersection-stopped event.
|
// Emit one intersection-started and one intersection-stopped event.
|
||||||
events.handle_collision_event(CollisionEvent::Started(toi.c1, toi.c2), None);
|
events.handle_collision_event(
|
||||||
events.handle_collision_event(CollisionEvent::Stopped(toi.c1, toi.c2, false), None);
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
use crate::dynamics::RigidBodyHandle;
|
use crate::dynamics::{RigidBodyHandle, RigidBodySet};
|
||||||
use crate::geometry::{ColliderHandle, Contact, ContactManifold};
|
use crate::geometry::{ColliderHandle, ColliderSet, Contact, ContactManifold};
|
||||||
use crate::math::{Point, Real, Vector};
|
use crate::math::{Point, Real, Vector};
|
||||||
use crate::pipeline::EventHandler;
|
use crate::pipeline::EventHandler;
|
||||||
|
use crate::prelude::CollisionEventFlags;
|
||||||
use parry::query::ContactManifoldsWorkspace;
|
use parry::query::ContactManifoldsWorkspace;
|
||||||
|
|
||||||
use super::CollisionEvent;
|
use super::CollisionEvent;
|
||||||
@@ -69,22 +70,36 @@ impl IntersectionPair {
|
|||||||
|
|
||||||
pub(crate) fn emit_start_event(
|
pub(crate) fn emit_start_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
bodies: &RigidBodySet,
|
||||||
|
colliders: &ColliderSet,
|
||||||
collider1: ColliderHandle,
|
collider1: ColliderHandle,
|
||||||
collider2: ColliderHandle,
|
collider2: ColliderHandle,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
) {
|
) {
|
||||||
self.start_event_emited = true;
|
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(
|
pub(crate) fn emit_stop_event(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
bodies: &RigidBodySet,
|
||||||
|
colliders: &ColliderSet,
|
||||||
collider1: ColliderHandle,
|
collider1: ColliderHandle,
|
||||||
collider2: ColliderHandle,
|
collider2: ColliderHandle,
|
||||||
events: &dyn EventHandler,
|
events: &dyn EventHandler,
|
||||||
) {
|
) {
|
||||||
self.start_event_emited = false;
|
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
|
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;
|
self.start_event_emited = true;
|
||||||
|
|
||||||
events.handle_collision_event(
|
events.handle_collision_event(
|
||||||
CollisionEvent::new(self.collider1, self.collider2, true),
|
bodies,
|
||||||
|
colliders,
|
||||||
|
CollisionEvent::Started(self.collider1, self.collider2, CollisionEventFlags::empty()),
|
||||||
Some(self),
|
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;
|
self.start_event_emited = false;
|
||||||
|
|
||||||
events.handle_collision_event(
|
events.handle_collision_event(
|
||||||
CollisionEvent::new(self.collider1, self.collider2, false),
|
bodies,
|
||||||
|
colliders,
|
||||||
|
CollisionEvent::Stopped(self.collider1, self.collider2, CollisionEventFlags::empty()),
|
||||||
Some(self),
|
Some(self),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,27 +50,28 @@ pub type PointProjection = parry::query::PointProjection;
|
|||||||
pub type TOI = parry::query::TOI;
|
pub type TOI = parry::query::TOI;
|
||||||
pub use parry::shape::SharedShape;
|
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)]
|
#[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 {
|
pub enum CollisionEvent {
|
||||||
/// Event occurring when two colliders start being in contact (or intersecting)
|
/// Event occurring when two colliders start colliding
|
||||||
Started(ColliderHandle, ColliderHandle),
|
Started(ColliderHandle, ColliderHandle, CollisionEventFlags),
|
||||||
/// Event occurring when two colliders stop being in contact (or intersecting).
|
/// Event occurring when two colliders stop colliding.
|
||||||
///
|
Stopped(ColliderHandle, ColliderHandle, CollisionEventFlags),
|
||||||
/// 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),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CollisionEvent {
|
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?
|
/// Is this a `Started` collision event?
|
||||||
pub fn started(self) -> bool {
|
pub fn started(self) -> bool {
|
||||||
matches!(self, CollisionEvent::Started(..))
|
matches!(self, CollisionEvent::Started(..))
|
||||||
@@ -84,14 +85,32 @@ impl CollisionEvent {
|
|||||||
/// The handle of the first collider involved in this collision event.
|
/// The handle of the first collider involved in this collision event.
|
||||||
pub fn collider1(self) -> ColliderHandle {
|
pub fn collider1(self) -> ColliderHandle {
|
||||||
match self {
|
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.
|
/// The handle of the second collider involved in this collision event.
|
||||||
pub fn collider2(self) -> ColliderHandle {
|
pub fn collider2(self) -> ColliderHandle {
|
||||||
match self {
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ use crate::pipeline::{
|
|||||||
ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext,
|
ActiveEvents, ActiveHooks, ContactModificationContext, EventHandler, PairFilterContext,
|
||||||
PhysicsHooks,
|
PhysicsHooks,
|
||||||
};
|
};
|
||||||
|
use crate::prelude::CollisionEventFlags;
|
||||||
use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
|
use parry::query::{DefaultQueryDispatcher, PersistentQueryDispatcher};
|
||||||
use parry::utils::IsometryOpt;
|
use parry::utils::IsometryOpt;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
@@ -317,14 +318,24 @@ impl NarrowPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pair.start_event_emited {
|
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 {
|
} else {
|
||||||
// If there is no island, don’t wake-up bodies, but do send the Stopped collision event.
|
// 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) {
|
for (a, b, pair) in self.contact_graph.interactions_with(contact_graph_id) {
|
||||||
if pair.start_event_emited {
|
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.
|
// Generate Stopped collision events for intersections.
|
||||||
for (a, b, pair) in self.intersection_graph.interactions_with(contact_graph_id) {
|
for (a, b, pair) in self.intersection_graph.interactions_with(contact_graph_id) {
|
||||||
if pair.start_event_emited {
|
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)
|
if (co1.flags.active_events | co2.flags.active_events)
|
||||||
.contains(ActiveEvents::COLLISION_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)
|
if (co1.flags.active_events | co2.flags.active_events)
|
||||||
.contains(ActiveEvents::COLLISION_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
|
&& had_intersection != edge.weight.intersecting
|
||||||
{
|
{
|
||||||
if 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 {
|
} 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 pair.has_any_active_contact != had_any_active_contact {
|
||||||
if active_events.contains(ActiveEvents::COLLISION_EVENTS) {
|
if active_events.contains(ActiveEvents::COLLISION_EVENTS) {
|
||||||
if pair.has_any_active_contact {
|
if pair.has_any_active_contact {
|
||||||
pair.emit_start_event(events);
|
pair.emit_start_event(bodies, colliders, events);
|
||||||
} else {
|
} else {
|
||||||
pair.emit_stop_event(events);
|
pair.emit_stop_event(bodies, colliders, events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use crate::geometry::{CollisionEvent, ContactPair};
|
use crate::dynamics::RigidBodySet;
|
||||||
|
use crate::geometry::{ColliderSet, CollisionEvent, ContactPair};
|
||||||
use crossbeam::channel::Sender;
|
use crossbeam::channel::Sender;
|
||||||
|
|
||||||
bitflags::bitflags! {
|
bitflags::bitflags! {
|
||||||
@@ -27,14 +28,29 @@ pub trait EventHandler: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// # Parameters
|
/// # Parameters
|
||||||
/// * `event` - The collision event.
|
/// * `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`
|
/// * `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
|
/// if at least one of the collider is a sensor (in which case no contact information
|
||||||
/// is ever computed).
|
/// 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 () {
|
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.
|
/// A collision event handler that collects events into a crossbeam channel.
|
||||||
@@ -50,7 +66,13 @@ impl ChannelEventCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EventHandler for 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);
|
let _ = self.event_sender.send(event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user