avian3d/collision/contact_types/contact_graph.rs
1use crate::collision::contact_types::ContactEdgeFlags;
2use crate::prelude::*;
3use crate::{
4 data_structures::{
5 graph::NodeIndex, pair_key::PairKey, sparse_secondary_map::SparseSecondaryEntityMap,
6 stable_graph::StableUnGraph,
7 },
8 dynamics::solver::constraint_graph::ContactManifoldHandle,
9};
10use bevy::{platform::collections::HashSet, prelude::*};
11
12use super::{ContactEdge, ContactId};
13
14/// A resource that stores all [`ContactEdge`]s in the physics world in an [undirected graph](StableUnGraph),
15/// and their corresponding [`ContactPair`]s.
16///
17/// Contact pairs exist between [colliders](Collider) that have intersecting [AABBs](ColliderAabb),
18/// even if the shapes themselves are not yet touching. Internally, pairs for active (non-sleeping) bodies
19/// are stored separately from pairs for sleeping bodies for optimization purposes.
20///
21/// For a simpler API that abstracts over this complexity, consider using the [`Collisions`]
22/// system parameter.
23///
24/// # Usage
25///
26/// The following methods can be used for querying collisions:
27///
28/// - [`get`](Self::get) and [`get_mut`](Self::get_mut)
29/// - [`iter_active`](Self::iter_active) and [`iter_active_mut`](Self::iter_active_mut)
30/// - [`iter_sleeping`](Self::iter_sleeping) and [`iter_sleeping_mut`](Self::iter_sleeping_mut)
31/// - [`contains`](Self::contains)
32/// - [`contact_pairs_with`](Self::contact_pairs_with)
33/// - [`entities_colliding_with`](Self::entities_colliding_with)
34///
35/// For example, to iterate over all collisions with a given entity:
36///
37/// ```
38#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
39#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
40/// use bevy::prelude::*;
41///
42/// #[derive(Component)]
43/// struct PressurePlate;
44///
45/// fn activate_pressure_plates(mut query: Query<Entity, With<PressurePlate>>, contact_graph: Res<ContactGraph>) {
46/// for pressure_plate in &query {
47/// // Compute the total impulse applied to the pressure plate.
48/// let mut total_impulse = 0.0;
49///
50/// for contact_pair in contact_graph.contact_pairs_with(pressure_plate) {
51/// total_impulse += contact_pair.total_normal_impulse_magnitude();
52/// }
53///
54/// if total_impulse > 5.0 {
55/// println!("Pressure plate activated!");
56/// }
57/// }
58/// }
59/// ```
60///
61/// While mutable access is allowed, contact modification and filtering should typically
62/// be done using [`CollisionHooks`]. See the documentation for more information.
63///
64/// For advanced usage, there are also methods such as [`get_edge`](Self::get_edge) and [`get_edge_mut`](Self::get_edge_mut)
65/// methods to access the [`ContactEdge`]s directly, along with variants that take a [`ContactId`] to access edges by their ID.
66///
67/// # Warning
68///
69/// For users, this resource is primarily for querying and reading collision data.
70///
71/// Directly adding, modifying, or removing contact pairs using this resource will *not* trigger any collision events,
72/// wake up the entities involved, or perform any other cleanup. Only make structural modifications if you know what you are doing.
73///
74/// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
75#[derive(Resource, Clone, Debug, Default)]
76pub struct ContactGraph {
77 // TODO: Can and should edges be between bodies instead of colliders?
78 // TODO: We could have a separate intersection graph for sensors.
79 // TODO: Make the fields private, but expose a public API through methods.
80 /// The internal undirected graph where nodes are entities and edges are contact pairs.
81 pub edges: ContactGraphInternal,
82
83 /// Contact pairs for awake dynamic and kinematic bodies.
84 pub(crate) active_pairs: Vec<ContactPair>,
85
86 /// Contact pairs for sleeping dynamic bodies.
87 pub(crate) sleeping_pairs: Vec<ContactPair>,
88
89 /// A set of all contact pairs for fast lookup.
90 ///
91 /// The [`PairKey`] is a unique pair of entity indices, sorted in ascending order,
92 /// concatenated into a single `u64` key.
93 ///
94 /// Two entities have a contact pair if they have intersecting AABBs.
95 pub(crate) pair_set: HashSet<PairKey>,
96
97 /// A map from entities to their corresponding node indices in the contact graph.
98 entity_to_node: SparseSecondaryEntityMap<NodeIndex>,
99
100 /// A reusable scratch buffer of contact IDs used when transferring contacts
101 /// between the active and sleeping sets, to avoid allocating on every call
102 /// to [`sleep_entity_with`] and [`wake_entity_with`].
103 ///
104 /// [`sleep_entity_with`]: Self::sleep_entity_with
105 /// [`wake_entity_with`]: Self::wake_entity_with
106 scratch_contact_ids: Vec<ContactId>,
107}
108
109/// An undirected graph where each node is an entity and each edge is a [`ContactEdge`].
110///
111/// The graph maintains stable indices for nodes and edges even when items are removed.
112///
113/// This is stored internally in the [`ContactGraph`] resource, which provides a higher-level API
114/// for working with contact pairs.
115pub type ContactGraphInternal = StableUnGraph<Entity, ContactEdge>;
116
117impl ContactGraph {
118 /// Returns the [`NodeIndex`] of the given entity in the contact graph.
119 ///
120 /// If the entity is not in the graph, `None` is returned.
121 #[inline]
122 pub fn entity_to_node(&self, entity: Entity) -> Option<NodeIndex> {
123 self.entity_to_node.get(entity).copied()
124 }
125
126 /// Returns the [`ContactEdge`] between two entities.
127 /// If the edge does not exist, `None` is returned.
128 ///
129 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
130 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
131 #[inline]
132 pub fn get_edge(&self, entity1: Entity, entity2: Entity) -> Option<&ContactEdge> {
133 let (Some(index1), Some(index2)) =
134 (self.entity_to_node(entity1), self.entity_to_node(entity2))
135 else {
136 return None;
137 };
138
139 self.edges
140 .find_edge(index1, index2)
141 .and_then(|edge| self.get_edge_by_id(edge.into()))
142 }
143
144 /// Returns the [`ContactEdge`] between two entities based on their IDs.
145 /// If the edge does not exist, `None` is returned.
146 ///
147 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
148 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
149 #[inline]
150 pub fn get_edge_by_id(&self, id: ContactId) -> Option<&ContactEdge> {
151 self.edges.edge_weight(id.into())
152 }
153
154 /// Returns a mutable reference to the [`ContactEdge`] between two entities.
155 /// If the edge does not exist, `None` is returned.
156 ///
157 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
158 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
159 #[inline]
160 pub fn get_edge_mut(&mut self, entity1: Entity, entity2: Entity) -> Option<&mut ContactEdge> {
161 let (Some(index1), Some(index2)) =
162 (self.entity_to_node(entity1), self.entity_to_node(entity2))
163 else {
164 return None;
165 };
166
167 self.edges
168 .find_edge(index1, index2)
169 .and_then(|edge| self.get_edge_mut_by_id(edge.into()))
170 }
171
172 /// Returns a mutable reference to the [`ContactEdge`] between two entities based on their IDs.
173 /// If the edge does not exist, `None` is returned.
174 ///
175 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
176 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
177 #[inline]
178 pub fn get_edge_mut_by_id(&mut self, id: ContactId) -> Option<&mut ContactEdge> {
179 self.edges.edge_weight_mut(id.into())
180 }
181
182 /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities.
183 /// If the pair does not exist, `None` is returned.
184 ///
185 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
186 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
187 #[inline]
188 pub fn get(&self, entity1: Entity, entity2: Entity) -> Option<(&ContactEdge, &ContactPair)> {
189 self.get_edge(entity1, entity2)
190 .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
191 }
192
193 /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
194 /// If the pair does not exist, `None` is returned.
195 ///
196 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
197 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
198 #[inline]
199 pub fn get_by_id(&self, id: ContactId) -> Option<(&ContactEdge, &ContactPair)> {
200 self.get_edge_by_id(id)
201 .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
202 }
203
204 /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities.
205 /// If the pair does not exist, `None` is returned.
206 ///
207 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
208 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
209 #[inline]
210 pub fn get_mut(
211 &mut self,
212 entity1: Entity,
213 entity2: Entity,
214 ) -> Option<(&mut ContactEdge, &mut ContactPair)> {
215 let (Some(index1), Some(index2)) =
216 (self.entity_to_node(entity1), self.entity_to_node(entity2))
217 else {
218 return None;
219 };
220
221 self.edges
222 .find_edge(index1, index2)
223 .and_then(|edge| self.get_mut_by_id(edge.into()))
224 }
225
226 /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
227 /// If the pair does not exist, `None` is returned.
228 ///
229 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
230 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
231 #[inline]
232 pub fn get_mut_by_id(&mut self, id: ContactId) -> Option<(&mut ContactEdge, &mut ContactPair)> {
233 self.edges.edge_weight_mut(id.into()).and_then(|edge| {
234 if edge.is_sleeping() {
235 self.sleeping_pairs
236 .get_mut(edge.pair_index)
237 .map(|pair| (edge, pair))
238 } else {
239 self.active_pairs
240 .get_mut(edge.pair_index)
241 .map(|pair| (edge, pair))
242 }
243 })
244 }
245
246 /// Returns the [`ContactPair`] between two entities based on the [`ContactEdge`].
247 /// If the pair does not exist, `None` is returned.
248 ///
249 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
250 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
251 #[inline]
252 pub fn get_pair_by_edge(&self, edge: &ContactEdge) -> Option<&ContactPair> {
253 if edge.is_sleeping() {
254 self.sleeping_pairs.get(edge.pair_index)
255 } else {
256 self.active_pairs.get(edge.pair_index)
257 }
258 }
259
260 /// Returns a mutable reference to the [`ContactPair`] between two entities based on the [`ContactEdge`].
261 /// If the pair does not exist, `None` is returned.
262 ///
263 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
264 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
265 #[inline]
266 pub fn get_pair_mut_by_edge(&mut self, edge: &ContactEdge) -> Option<&mut ContactPair> {
267 if edge.is_sleeping() {
268 self.sleeping_pairs.get_mut(edge.pair_index)
269 } else {
270 self.active_pairs.get_mut(edge.pair_index)
271 }
272 }
273
274 /// Returns a [`ContactManifold`] of a contact pair based on the [`ContactManifoldHandle`].
275 /// If the manifold does not exist, `None` is returned.
276 #[inline]
277 pub fn get_manifold(&self, handle: ContactManifoldHandle) -> Option<&ContactManifold> {
278 let contact_pair = self.get_by_id(handle.contact_id)?.1;
279 contact_pair.manifolds.get(handle.manifold_index)
280 }
281
282 /// Returns a mutable reference to a [`ContactManifold`] of a contact pair based on the [`ContactManifoldHandle`].
283 /// If the manifold does not exist, `None` is returned.
284 #[inline]
285 pub fn get_manifold_mut(
286 &mut self,
287 handle: ContactManifoldHandle,
288 ) -> Option<&mut ContactManifold> {
289 let contact_pair = self.get_mut_by_id(handle.contact_id)?.1;
290 contact_pair.manifolds.get_mut(handle.manifold_index)
291 }
292
293 /// Returns `true` if the given entities have a contact pair.
294 ///
295 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
296 /// even if the shapes themselves are not yet touching.
297 #[inline]
298 pub fn contains(&self, entity1: Entity, entity2: Entity) -> bool {
299 self.contains_key(&PairKey::new(entity1.index_u32(), entity2.index_u32()))
300 }
301
302 /// Returns `true` if the given pair key is in the contact graph.
303 ///
304 /// The pair key should be equivalent to `PairKey::new(entity1.index_u32(), entity2.index_u32())`.
305 ///
306 /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
307 /// If the key is not available, consider using [`contains`](Self::contains) instead.
308 #[inline]
309 pub fn contains_key(&self, pair_key: &PairKey) -> bool {
310 self.pair_set.contains(pair_key)
311 }
312
313 /// Returns a slice over all active (non-sleeping) contact pairs.
314 #[inline]
315 pub fn active_pairs(&self) -> &[ContactPair] {
316 &self.active_pairs
317 }
318
319 /// Returns a slice over all sleeping contact pairs.
320 #[inline]
321 pub fn sleeping_pairs(&self) -> &[ContactPair] {
322 &self.sleeping_pairs
323 }
324
325 /// Returns a mutable slice over all active (non-sleeping) contact pairs.
326 #[inline]
327 pub fn active_pairs_mut(&mut self) -> &mut [ContactPair] {
328 &mut self.active_pairs
329 }
330
331 /// Returns a mutable slice over all sleeping contact pairs.
332 #[inline]
333 pub fn sleeping_pairs_mut(&mut self) -> &mut [ContactPair] {
334 &mut self.sleeping_pairs
335 }
336
337 /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs.
338 ///
339 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
340 /// even if the shapes themselves are not yet touching.
341 ///
342 /// If you only want touching contacts, use [`iter_active_touching`](Self::iter_active_touching) instead.
343 #[inline]
344 pub fn iter_active(&self) -> impl Iterator<Item = &ContactPair> {
345 self.active_pairs.iter()
346 }
347
348 /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs
349 /// that are currently touching.
350 ///
351 /// This is a subset of [`iter_active`](Self::iter_active) that only includes pairs where the colliders are touching.
352 #[inline]
353 pub fn iter_active_touching(&self) -> impl Iterator<Item = &ContactPair> {
354 self.iter_active()
355 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
356 }
357
358 /// Returns a iterator yielding mutable access to all contact pairs.
359 ///
360 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
361 /// even if the shapes themselves are not yet touching.
362 ///
363 /// If you only want touching contacts, use [`iter_active_touching_mut`](Self::iter_active_touching_mut) instead.
364 #[inline]
365 pub fn iter_active_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
366 self.active_pairs.iter_mut()
367 }
368
369 /// Returns an iterator yielding mutable access to all active (non-sleeping) contact pairs
370 /// that are currently touching.
371 ///
372 /// This is a subset of [`iter_active_mut`](Self::iter_active_mut) that only includes pairs where the colliders are touching.
373 #[inline]
374 pub fn iter_active_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
375 self.iter_active_mut()
376 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
377 }
378
379 /// Returns an iterator yielding immutable access to all sleeping contact pairs.
380 ///
381 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
382 /// even if the shapes themselves are not yet touching.
383 ///
384 /// If you only want touching contacts, use [`iter_sleeping_touching`](Self::iter_sleeping_touching) instead.
385 #[inline]
386 pub fn iter_sleeping(&self) -> impl Iterator<Item = &ContactPair> {
387 self.sleeping_pairs.iter()
388 }
389
390 /// Returns an iterator yielding immutable access to all sleeping contact pairs
391 /// that are currently touching.
392 ///
393 /// This is a subset of [`iter_sleeping`](Self::iter_sleeping) that only includes pairs where the colliders are touching.
394 #[inline]
395 pub fn iter_sleeping_touching(&self) -> impl Iterator<Item = &ContactPair> {
396 self.iter_sleeping()
397 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
398 }
399
400 /// Returns an iterator yielding mutable access to all sleeping contact pairs.
401 ///
402 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
403 /// even if the shapes themselves are not yet touching.
404 ///
405 /// If you only want touching contacts, use [`iter_sleeping_touching_mut`](Self::iter_sleeping_touching_mut) instead.
406 #[inline]
407 pub fn iter_sleeping_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
408 self.sleeping_pairs.iter_mut()
409 }
410
411 /// Returns an iterator yielding mutable access to all sleeping contact pairs
412 /// that are currently touching.
413 ///
414 /// This is a subset of [`iter_sleeping_mut`](Self::iter_sleeping_mut) that only includes pairs where the colliders are touching.
415 #[inline]
416 pub fn iter_sleeping_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
417 self.iter_sleeping_mut()
418 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
419 }
420
421 /// Returns an iterator yielding immutable access to all contact edges involving the given entity.
422 #[inline]
423 pub fn contact_edges_with(&self, entity: Entity) -> impl Iterator<Item = &ContactEdge> {
424 let index = self.entity_to_node(entity);
425 if let Some(index) = index {
426 itertools::Either::Left(self.edges.edge_weights(index))
427 } else {
428 itertools::Either::Right(core::iter::empty())
429 }
430 }
431
432 /// Returns an iterator yielding mutable access to all contact edges involving the given entity.
433 #[inline]
434 pub fn contact_edges_with_mut(
435 &mut self,
436 entity: Entity,
437 ) -> impl Iterator<Item = &mut ContactEdge> {
438 let index = self.entity_to_node(entity);
439 if let Some(index) = index {
440 itertools::Either::Left(self.edges.edge_weights_mut(index))
441 } else {
442 itertools::Either::Right(core::iter::empty())
443 }
444 }
445
446 /// Returns an iterator yielding immutable access to all contact pairs involving the given entity.
447 ///
448 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
449 /// even if the shapes themselves are not yet touching.
450 ///
451 /// Use [`ContactEdge::is_touching`](ContactEdge::is_touching) to determine if the actual collider shapes are touching.
452 // TODO: A mutable version of this could be useful, but it would probably require some `unsafe`.
453 #[inline]
454 pub fn contact_pairs_with(&self, entity: Entity) -> impl Iterator<Item = &ContactPair> {
455 self.contact_edges_with(entity)
456 .filter_map(move |edge| self.get_pair_by_edge(edge))
457 }
458
459 /// Returns an iterator yielding immutable access to all entities that have a contact pair with the given entity.
460 ///
461 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
462 /// even if the shapes themselves are not yet touching.
463 #[inline]
464 pub fn entities_colliding_with(&self, entity: Entity) -> impl Iterator<Item = Entity> + '_ {
465 self.entity_to_node
466 .get(entity)
467 .into_iter()
468 .flat_map(move |&index| {
469 self.edges
470 .neighbors(index)
471 .map(|index| *self.edges.node_weight(index).unwrap())
472 })
473 }
474
475 /// Creates a [`ContactEdge`] between two entities and adds an associated [`ContactPair`]
476 /// to the list of active pairs.
477 ///
478 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
479 ///
480 /// # Warning
481 ///
482 /// Creating a contact edge with this method will *not* trigger any collision events
483 /// or wake up the entities involved. Only use this method if you know what you are doing.
484 #[inline]
485 pub fn add_edge(&mut self, contact_edge: ContactEdge) -> Option<ContactId> {
486 let body1 = contact_edge.body1;
487 let body2 = contact_edge.body2;
488 self.add_edge_with(contact_edge, |pair| {
489 pair.body1 = body1;
490 pair.body2 = body2;
491 })
492 }
493
494 /// Creates a [`ContactEdge`] between two entities, calling the provided callback
495 /// to initialize the associated [`ContactPair`] in the list of active pairs.
496 ///
497 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
498 ///
499 /// # Warning
500 ///
501 /// Creating a contact edge with this method will *not* trigger any collision events
502 /// or wake up the entities involved. Only use this method if you know what you are doing.
503 #[inline]
504 pub fn add_edge_with<F>(
505 &mut self,
506 contact_edge: ContactEdge,
507 pair_callback: F,
508 ) -> Option<ContactId>
509 where
510 F: FnMut(&mut ContactPair),
511 {
512 let pair_key = PairKey::new(
513 contact_edge.collider1.index_u32(),
514 contact_edge.collider2.index_u32(),
515 );
516 self.add_edge_and_key_with(contact_edge, pair_key, pair_callback)
517 }
518
519 /// Creates a [`ContactEdge`] between two entities with the given pair key, calling the provided callback
520 /// to initialize the associated [`ContactPair`] in the list of active pairs.
521 ///
522 /// The key must be equivalent to `PairKey::new(contacts.entity1.index_u32(), contacts.entity2.index_u32())`.
523 ///
524 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
525 ///
526 /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
527 /// If the key is not available, consider using [`add_edge`](Self::add_edge) or [`add_edge_with`](Self::add_edge_with) instead.
528 ///
529 /// # Warning
530 ///
531 /// Creating a contact edge with this method will *not* trigger any collision events
532 /// or wake up the entities involved. Only use this method if you know what you are doing.
533 #[inline]
534 pub fn add_edge_and_key_with<F>(
535 &mut self,
536 contact_edge: ContactEdge,
537 pair_key: PairKey,
538 mut pair_callback: F,
539 ) -> Option<ContactId>
540 where
541 F: FnMut(&mut ContactPair),
542 {
543 // Add the pair to the pair set for fast lookup.
544 if !self.pair_set.insert(pair_key) {
545 // The pair already exists.
546 return None;
547 }
548
549 let collider1 = contact_edge.collider1;
550 let collider2 = contact_edge.collider2;
551
552 // Get the indices of the entities in the graph.
553 let index1 = self
554 .entity_to_node
555 .get_or_insert_with(collider1, || self.edges.add_node(collider1));
556 let index2 = self
557 .entity_to_node
558 .get_or_insert_with(collider2, || self.edges.add_node(collider2));
559
560 // Add the edge to the graph.
561 let edge_id = ContactId(self.edges.add_edge(index1, index2, contact_edge).0);
562
563 // Create the contact pair. Contacts are created as active.
564 let mut pair = ContactPair::new(collider1, collider2, edge_id);
565
566 // Call the pair callback to allow for custom initialization.
567 pair_callback(&mut pair);
568
569 let pair_index = self.active_pairs.len();
570 self.active_pairs.push(pair);
571
572 // Set the contact ID and pair index of the edge.
573 let edge = self.edges.edge_weight_mut(edge_id.into()).unwrap();
574 edge.id = edge_id;
575 edge.pair_index = pair_index;
576
577 Some(edge_id)
578 }
579
580 /// Removes a [`ContactEdge`] between two entites and returns its value.
581 ///
582 /// # Warning
583 ///
584 /// Removing a contact edge with this method will *not* trigger any collision events
585 /// or wake up the entities involved. Only use this method if you know what you are doing.
586 ///
587 /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
588 #[inline]
589 pub fn remove_edge(&mut self, entity1: Entity, entity2: Entity) -> Option<ContactEdge> {
590 let (Some(index1), Some(index2)) =
591 (self.entity_to_node(entity1), self.entity_to_node(entity2))
592 else {
593 return None;
594 };
595
596 // Remove the edge from the graph.
597 self.edges.find_edge(index1, index2).and_then(|edge_id| {
598 let pair_key = PairKey::new(entity1.index_u32(), entity2.index_u32());
599 self.remove_edge_by_id(&pair_key, edge_id.into())
600 })
601 }
602
603 /// Removes a [`ContactEdge`] based on its pair key and ID and returns its value.
604 ///
605 /// # Warning
606 ///
607 /// Removing a contact edge with this method will *not* trigger any collision events
608 /// or wake up the entities involved. Only use this method if you know what you are doing.
609 ///
610 /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
611 #[inline]
612 pub fn remove_edge_by_id(&mut self, pair_key: &PairKey, id: ContactId) -> Option<ContactEdge> {
613 // Remove the pair from the pair set.
614 self.pair_set.remove(pair_key);
615
616 // Remove the edge from the graph.
617 let edge = self.edges.remove_edge(id.into())?;
618 let edge_count = self.edges.raw_edges().len();
619
620 // Remove the contact pair from the active or sleeping pairs.
621 let pair_index = edge.pair_index;
622 let contact_pairs = if edge.is_sleeping() {
623 &mut self.sleeping_pairs
624 } else {
625 &mut self.active_pairs
626 };
627
628 let moved_index = contact_pairs.len() - 1;
629 contact_pairs.swap_remove(pair_index);
630
631 if moved_index != pair_index {
632 // Fix moved pair index.
633 let moved_contact_id = contact_pairs[pair_index].contact_id;
634 let moved_edge = self
635 .get_edge_mut_by_id(moved_contact_id)
636 .unwrap_or_else(|| {
637 panic!("error when removing contact pair {id:?} with pair index {pair_index:?}: moved edge {moved_contact_id:?} not found in contact graph with {edge_count} edges and {moved_index} sleeping pairs")
638 });
639 debug_assert!(moved_edge.pair_index == moved_index);
640 moved_edge.pair_index = pair_index;
641 }
642
643 Some(edge)
644 }
645
646 /// Removes the collider of the given entity from the contact graph, calling the given callback
647 /// for each [`ContactEdge`] right before it is removed.
648 ///
649 /// # Warning
650 ///
651 /// Removing a collider with this method will *not* trigger any collision events
652 /// or wake up the entities involved. Only use this method if you know what you are doing.
653 #[inline]
654 pub fn remove_collider_with<F>(&mut self, entity: Entity, mut edge_callback: F)
655 where
656 F: FnMut(&mut StableUnGraph<Entity, ContactEdge>, ContactId),
657 {
658 // Remove the entity from the entity-to-node mapping,
659 // and get the index of the node in the graph.
660 let Some(index) = self.entity_to_node.remove(entity) else {
661 return;
662 };
663
664 // Remove the entity from the graph.
665 self.edges.remove_node_with(index, |graph, edge_index| {
666 let contact_id: ContactId = edge_index.into();
667 let contact_edge = graph.edge_weight(edge_index).unwrap_or_else(|| {
668 panic!("contact edge {contact_id:?} not found in contact graph")
669 });
670 let pair_key = PairKey::new(
671 contact_edge.collider1.index_u32(),
672 contact_edge.collider2.index_u32(),
673 );
674 let pair_index = contact_edge.pair_index;
675 let contact_pairs = if contact_edge.is_sleeping() {
676 &mut self.sleeping_pairs
677 } else {
678 &mut self.active_pairs
679 };
680
681 edge_callback(graph, contact_id);
682
683 // Remove the contact pair from the active or sleeping pairs.
684 let moved_index = contact_pairs.len() - 1;
685 let _ = contact_pairs.swap_remove(pair_index);
686
687 // Fix moved pair index.
688 if moved_index != pair_index {
689 let moved_contact_id = contact_pairs[pair_index].contact_id;
690 let moved_edge = graph
691 .edge_weight_mut(moved_contact_id.into())
692 .unwrap_or_else(|| {
693 panic!("moved edge {moved_contact_id:?} not found in contact graph")
694 });
695 debug_assert!(moved_edge.pair_index == moved_index);
696 moved_edge.pair_index = pair_index;
697 }
698
699 // Remove the pair from the pair set.
700 self.pair_set.remove(&pair_key);
701 });
702
703 // Removing the node swapped the last node to its place,
704 // so we need to remap the entity-to-node mapping of the swapped node.
705 if let Some(swapped) = self.edges.node_weight(index).copied() {
706 let swapped_index = self
707 .entity_to_node
708 .get_mut(swapped)
709 // This should never panic.
710 .expect("swapped entity has no entity-to-node mapping");
711 *swapped_index = index;
712 }
713 }
714
715 /// Transfers the contacts of a body from the sleeping contacts to the active contacts,
716 /// calling the given callback for each [`ContactPair`] that is moved to active contacts.
717 #[inline]
718 pub fn wake_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
719 where
720 F: FnMut(&mut ContactGraph, &ContactPair),
721 {
722 // Get the index of the entity in the graph.
723 let Some(index) = self.entity_to_node(entity) else {
724 return;
725 };
726
727 // Find all edges connected to the entity.
728 let mut contact_ids = core::mem::take(&mut self.scratch_contact_ids);
729 contact_ids.extend(
730 self.edges
731 .edge_weights(index)
732 .filter_map(|edge| edge.is_sleeping().then_some(edge.id)),
733 );
734
735 // Iterate over the edges and move sleeping contacts to active contacts.
736 for &id in &contact_ids {
737 let edge = self
738 .edges
739 .edge_weight_mut(id.into())
740 .expect("edge should exist");
741
742 let pair_index = edge.pair_index;
743
744 // Remove the sleeping contact pair.
745 let moved_index = self.sleeping_pairs.len() - 1;
746 let transferred_pair = self.sleeping_pairs.swap_remove(pair_index);
747
748 // Update the pair index of the edge.
749 edge.pair_index = self.active_pairs.len();
750
751 // Set the edge to active.
752 edge.flags.set(ContactEdgeFlags::SLEEPING, false);
753
754 // Call the pair callback.
755 pair_callback(self, &transferred_pair);
756
757 // Add the transferred pair to the active pairs.
758 self.active_pairs.push(transferred_pair);
759
760 // Fix moved edge.
761 if moved_index != pair_index {
762 let moved_contact_id = self.sleeping_pairs[pair_index].contact_id;
763 let moved_edge = self
764 .get_edge_mut_by_id(moved_contact_id)
765 .unwrap_or_else(|| {
766 panic!("error when waking contact pair {moved_contact_id:?} (other {id:?}) with pair index {pair_index:?}: moved edge not found in contact graph")
767 });
768 debug_assert!(moved_edge.pair_index == moved_index);
769 moved_edge.pair_index = pair_index;
770 }
771 }
772
773 // Restore the scratch buffer.
774 contact_ids.clear();
775 self.scratch_contact_ids = contact_ids;
776 }
777
778 /// Transfers the contacts of a body from the active contacts to the sleeping contacts,
779 /// calling the given callback for each [`ContactPair`] that is moved to sleeping contacts.
780 ///
781 /// A contact is only moved to the sleeping set if `should_sleep` returns `true` for the
782 /// other body in the pair. This prevents a non-touching pair between this body and a still-awake
783 /// body from being put to sleep. A pair may sleep only once *both* of its bodies are asleep or immovable.
784 #[inline]
785 pub fn sleep_entity_with<F, S>(&mut self, entity: Entity, mut pair_callback: F, should_sleep: S)
786 where
787 F: FnMut(&mut ContactGraph, &ContactPair),
788 S: Fn(Option<Entity>) -> bool,
789 {
790 // Get the index of the entity in the graph.
791 let Some(index) = self.entity_to_node(entity) else {
792 return;
793 };
794
795 // Find all edges connected to the entity.
796 let mut contact_ids = core::mem::take(&mut self.scratch_contact_ids);
797 contact_ids.extend(
798 self.edges
799 .edge_weights(index)
800 .filter_map(|edge| (!edge.is_sleeping()).then_some(edge.id)),
801 );
802
803 // Iterate over the edges and move active contacts to sleeping contacts.
804 for &id in &contact_ids {
805 let edge = self
806 .edges
807 .edge_weight_mut(id.into())
808 .expect("edge should exist");
809
810 // Only sleep the contact if the other body is also asleep or immovable.
811 // Otherwise the pair must stay active so the narrow phase keeps updating it.
812 let other_body = if edge.collider1 == entity {
813 edge.body2
814 } else {
815 edge.body1
816 };
817 if !should_sleep(other_body) {
818 continue;
819 }
820
821 let pair_index = edge.pair_index;
822
823 // Remove the active contact pair.
824 let moved_index = self.active_pairs.len() - 1;
825 let transferred_pair = self.active_pairs.swap_remove(pair_index);
826
827 // Update the pair index of the edge.
828 edge.pair_index = self.sleeping_pairs.len();
829
830 // Set the edge to sleeping.
831 edge.flags.set(ContactEdgeFlags::SLEEPING, true);
832
833 // Call the edge callback.
834 pair_callback(self, &transferred_pair);
835
836 // Add the transferred pair to the sleeping pairs.
837 self.sleeping_pairs.push(transferred_pair);
838
839 // Fix moved edge.
840 if moved_index != pair_index {
841 let moved_contact_id = self.active_pairs[pair_index].contact_id;
842 let moved_edge = self
843 .get_edge_mut_by_id(moved_contact_id)
844 .unwrap_or_else(|| {
845 panic!("error when sleeping contact pair {moved_contact_id:?} with pair index {pair_index:?}: moved edge not found in contact graph")
846 });
847 debug_assert!(moved_edge.pair_index == moved_index);
848 moved_edge.pair_index = pair_index;
849 }
850 }
851
852 // Restore the scratch buffer.
853 contact_ids.clear();
854 self.scratch_contact_ids = contact_ids;
855 }
856
857 /// Clears all contact pairs and the contact graph.
858 ///
859 /// # Warning
860 ///
861 /// Clearing contact pairs with this method will *not* trigger any collision events
862 /// or wake up the entities involved. Only use this method if you know what you are doing.
863 ///
864 /// Additionally, this does *not* clear the [`ConstraintGraph`]! You should additionally
865 /// call [`ConstraintGraph::clear`].
866 ///
867 /// [`ConstraintGraph`]: crate::dynamics::solver::constraint_graph::ConstraintGraph
868 /// [`ConstraintGraph::clear`]: crate::dynamics::solver::constraint_graph::ConstraintGraph::clear
869 #[inline]
870 pub fn clear(&mut self) {
871 self.edges.clear();
872 self.active_pairs.clear();
873 self.sleeping_pairs.clear();
874 self.pair_set.clear();
875 self.entity_to_node.clear();
876 }
877}