avian2d/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
101/// An undirected graph where each node is an entity and each edge is a [`ContactEdge`].
102///
103/// The graph maintains stable indices for nodes and edges even when items are removed.
104///
105/// This is stored internally in the [`ContactGraph`] resource, which provides a higher-level API
106/// for working with contact pairs.
107pub type ContactGraphInternal = StableUnGraph<Entity, ContactEdge>;
108
109impl ContactGraph {
110 /// Returns the [`NodeIndex`] of the given entity in the contact graph.
111 ///
112 /// If the entity is not in the graph, `None` is returned.
113 #[inline]
114 pub fn entity_to_node(&self, entity: Entity) -> Option<NodeIndex> {
115 self.entity_to_node.get(entity).copied()
116 }
117
118 /// Returns the [`ContactEdge`] between two entities.
119 /// If the edge does not exist, `None` is returned.
120 ///
121 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
122 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
123 #[inline]
124 pub fn get_edge(&self, entity1: Entity, entity2: Entity) -> Option<&ContactEdge> {
125 let (Some(index1), Some(index2)) =
126 (self.entity_to_node(entity1), self.entity_to_node(entity2))
127 else {
128 return None;
129 };
130
131 self.edges
132 .find_edge(index1, index2)
133 .and_then(|edge| self.get_edge_by_id(edge.into()))
134 }
135
136 /// Returns the [`ContactEdge`] between two entities based on their IDs.
137 /// If the edge does not exist, `None` is returned.
138 ///
139 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
140 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
141 #[inline]
142 pub fn get_edge_by_id(&self, id: ContactId) -> Option<&ContactEdge> {
143 self.edges.edge_weight(id.into())
144 }
145
146 /// Returns a mutable reference to the [`ContactEdge`] between two entities.
147 /// If the edge does not exist, `None` is returned.
148 ///
149 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
150 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
151 #[inline]
152 pub fn get_edge_mut(&mut self, entity1: Entity, entity2: Entity) -> Option<&mut ContactEdge> {
153 let (Some(index1), Some(index2)) =
154 (self.entity_to_node(entity1), self.entity_to_node(entity2))
155 else {
156 return None;
157 };
158
159 self.edges
160 .find_edge(index1, index2)
161 .and_then(|edge| self.get_edge_mut_by_id(edge.into()))
162 }
163
164 /// Returns a mutable reference to the [`ContactEdge`] between two entities based on their IDs.
165 /// If the edge does not exist, `None` is returned.
166 ///
167 /// A contact edge exists between two entities if their [`ColliderAabb`]s intersect.
168 /// Use [`ContactEdge::is_touching`] to determine if the actual collider shapes are touching.
169 #[inline]
170 pub fn get_edge_mut_by_id(&mut self, id: ContactId) -> Option<&mut ContactEdge> {
171 self.edges.edge_weight_mut(id.into())
172 }
173
174 /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities.
175 /// If the pair does not exist, `None` is returned.
176 ///
177 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
178 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
179 #[inline]
180 pub fn get(&self, entity1: Entity, entity2: Entity) -> Option<(&ContactEdge, &ContactPair)> {
181 self.get_edge(entity1, entity2)
182 .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
183 }
184
185 /// Returns the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
186 /// If the pair does not exist, `None` is returned.
187 ///
188 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
189 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
190 #[inline]
191 pub fn get_by_id(&self, id: ContactId) -> Option<(&ContactEdge, &ContactPair)> {
192 self.get_edge_by_id(id)
193 .and_then(|edge| self.get_pair_by_edge(edge).map(|pair| (edge, pair)))
194 }
195
196 /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities.
197 /// If the pair does not exist, `None` is returned.
198 ///
199 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
200 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
201 #[inline]
202 pub fn get_mut(
203 &mut self,
204 entity1: Entity,
205 entity2: Entity,
206 ) -> Option<(&mut ContactEdge, &mut ContactPair)> {
207 let (Some(index1), Some(index2)) =
208 (self.entity_to_node(entity1), self.entity_to_node(entity2))
209 else {
210 return None;
211 };
212
213 self.edges
214 .find_edge(index1, index2)
215 .and_then(|edge| self.get_mut_by_id(edge.into()))
216 }
217
218 /// Returns a mutable reference to the [`ContactEdge`] and [`ContactPair`] between two entities based on the contact ID.
219 /// If the pair does not exist, `None` is returned.
220 ///
221 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
222 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
223 #[inline]
224 pub fn get_mut_by_id(&mut self, id: ContactId) -> Option<(&mut ContactEdge, &mut ContactPair)> {
225 self.edges.edge_weight_mut(id.into()).and_then(|edge| {
226 if edge.is_sleeping() {
227 self.sleeping_pairs
228 .get_mut(edge.pair_index)
229 .map(|pair| (edge, pair))
230 } else {
231 self.active_pairs
232 .get_mut(edge.pair_index)
233 .map(|pair| (edge, pair))
234 }
235 })
236 }
237
238 /// Returns the [`ContactPair`] between two entities based on the [`ContactEdge`].
239 /// If the pair does not exist, `None` is returned.
240 ///
241 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
242 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
243 #[inline]
244 pub fn get_pair_by_edge(&self, edge: &ContactEdge) -> Option<&ContactPair> {
245 if edge.is_sleeping() {
246 self.sleeping_pairs.get(edge.pair_index)
247 } else {
248 self.active_pairs.get(edge.pair_index)
249 }
250 }
251
252 /// Returns a mutable reference to the [`ContactPair`] between two entities based on the [`ContactEdge`].
253 /// If the pair does not exist, `None` is returned.
254 ///
255 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
256 /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
257 #[inline]
258 pub fn get_pair_mut_by_edge(&mut self, edge: &ContactEdge) -> Option<&mut ContactPair> {
259 if edge.is_sleeping() {
260 self.sleeping_pairs.get_mut(edge.pair_index)
261 } else {
262 self.active_pairs.get_mut(edge.pair_index)
263 }
264 }
265
266 /// Returns a [`ContactManifold`] of a contact pair based on the [`ContactManifoldHandle`].
267 /// If the manifold does not exist, `None` is returned.
268 #[inline]
269 pub fn get_manifold(&self, handle: ContactManifoldHandle) -> Option<&ContactManifold> {
270 let contact_pair = self.get_by_id(handle.contact_id)?.1;
271 contact_pair.manifolds.get(handle.manifold_index)
272 }
273
274 /// Returns a mutable reference to 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_mut(
278 &mut self,
279 handle: ContactManifoldHandle,
280 ) -> Option<&mut ContactManifold> {
281 let contact_pair = self.get_mut_by_id(handle.contact_id)?.1;
282 contact_pair.manifolds.get_mut(handle.manifold_index)
283 }
284
285 /// Returns `true` if the given entities have a contact pair.
286 ///
287 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
288 /// even if the shapes themselves are not yet touching.
289 #[inline]
290 pub fn contains(&self, entity1: Entity, entity2: Entity) -> bool {
291 self.contains_key(&PairKey::new(entity1.index(), entity2.index()))
292 }
293
294 /// Returns `true` if the given pair key is in the contact graph.
295 ///
296 /// The pair key should be equivalent to `PairKey::new(entity1.index(), entity2.index())`.
297 ///
298 /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
299 /// If the key is not available, consider using [`contains`](Self::contains) instead.
300 #[inline]
301 pub fn contains_key(&self, pair_key: &PairKey) -> bool {
302 self.pair_set.contains(pair_key)
303 }
304
305 /// Returns a slice over all active (non-sleeping) contact pairs.
306 #[inline]
307 pub fn active_pairs(&self) -> &[ContactPair] {
308 &self.active_pairs
309 }
310
311 /// Returns a slice over all sleeping contact pairs.
312 #[inline]
313 pub fn sleeping_pairs(&self) -> &[ContactPair] {
314 &self.sleeping_pairs
315 }
316
317 /// Returns a mutable slice over all active (non-sleeping) contact pairs.
318 #[inline]
319 pub fn active_pairs_mut(&mut self) -> &mut [ContactPair] {
320 &mut self.active_pairs
321 }
322
323 /// Returns a mutable slice over all sleeping contact pairs.
324 #[inline]
325 pub fn sleeping_pairs_mut(&mut self) -> &mut [ContactPair] {
326 &mut self.sleeping_pairs
327 }
328
329 /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs.
330 ///
331 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
332 /// even if the shapes themselves are not yet touching.
333 ///
334 /// If you only want touching contacts, use [`iter_active_touching`](Self::iter_active_touching) instead.
335 #[inline]
336 pub fn iter_active(&self) -> impl Iterator<Item = &ContactPair> {
337 self.active_pairs.iter()
338 }
339
340 /// Returns an iterator yielding immutable access to all active (non-sleeping) contact pairs
341 /// that are currently touching.
342 ///
343 /// This is a subset of [`iter_active`](Self::iter_active) that only includes pairs where the colliders are touching.
344 #[inline]
345 pub fn iter_active_touching(&self) -> impl Iterator<Item = &ContactPair> {
346 self.iter_active()
347 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
348 }
349
350 /// Returns a iterator yielding mutable access to all contact pairs.
351 ///
352 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
353 /// even if the shapes themselves are not yet touching.
354 ///
355 /// If you only want touching contacts, use [`iter_active_touching_mut`](Self::iter_active_touching_mut) instead.
356 #[inline]
357 pub fn iter_active_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
358 self.active_pairs.iter_mut()
359 }
360
361 /// Returns an iterator yielding mutable access to all active (non-sleeping) contact pairs
362 /// that are currently touching.
363 ///
364 /// This is a subset of [`iter_active_mut`](Self::iter_active_mut) that only includes pairs where the colliders are touching.
365 #[inline]
366 pub fn iter_active_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
367 self.iter_active_mut()
368 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
369 }
370
371 /// Returns an iterator yielding immutable access to all sleeping contact pairs.
372 ///
373 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
374 /// even if the shapes themselves are not yet touching.
375 ///
376 /// If you only want touching contacts, use [`iter_sleeping_touching`](Self::iter_sleeping_touching) instead.
377 #[inline]
378 pub fn iter_sleeping(&self) -> impl Iterator<Item = &ContactPair> {
379 self.sleeping_pairs.iter()
380 }
381
382 /// Returns an iterator yielding immutable access to all sleeping contact pairs
383 /// that are currently touching.
384 ///
385 /// This is a subset of [`iter_sleeping`](Self::iter_sleeping) that only includes pairs where the colliders are touching.
386 #[inline]
387 pub fn iter_sleeping_touching(&self) -> impl Iterator<Item = &ContactPair> {
388 self.iter_sleeping()
389 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
390 }
391
392 /// Returns an iterator yielding mutable access to all sleeping contact pairs.
393 ///
394 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
395 /// even if the shapes themselves are not yet touching.
396 ///
397 /// If you only want touching contacts, use [`iter_sleeping_touching_mut`](Self::iter_sleeping_touching_mut) instead.
398 #[inline]
399 pub fn iter_sleeping_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
400 self.sleeping_pairs.iter_mut()
401 }
402
403 /// Returns an iterator yielding mutable access to all sleeping contact pairs
404 /// that are currently touching.
405 ///
406 /// This is a subset of [`iter_sleeping_mut`](Self::iter_sleeping_mut) that only includes pairs where the colliders are touching.
407 #[inline]
408 pub fn iter_sleeping_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
409 self.iter_sleeping_mut()
410 .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
411 }
412
413 /// Returns an iterator yielding immutable access to all contact edges involving the given entity.
414 #[inline]
415 pub fn contact_edges_with(&self, entity: Entity) -> impl Iterator<Item = &ContactEdge> {
416 let index = self.entity_to_node(entity);
417 if let Some(index) = index {
418 itertools::Either::Left(self.edges.edge_weights(index))
419 } else {
420 itertools::Either::Right(core::iter::empty())
421 }
422 }
423
424 /// Returns an iterator yielding mutable access to all contact edges involving the given entity.
425 #[inline]
426 pub fn contact_edges_with_mut(
427 &mut self,
428 entity: Entity,
429 ) -> impl Iterator<Item = &mut ContactEdge> {
430 let index = self.entity_to_node(entity);
431 if let Some(index) = index {
432 itertools::Either::Left(self.edges.edge_weights_mut(index))
433 } else {
434 itertools::Either::Right(core::iter::empty())
435 }
436 }
437
438 /// Returns an iterator yielding immutable access to all contact pairs involving the given entity.
439 ///
440 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
441 /// even if the shapes themselves are not yet touching.
442 ///
443 /// Use [`ContactEdge::is_touching`](ContactEdge::is_touching) to determine if the actual collider shapes are touching.
444 // TODO: A mutable version of this could be useful, but it would probably require some `unsafe`.
445 #[inline]
446 pub fn contact_pairs_with(&self, entity: Entity) -> impl Iterator<Item = &ContactPair> {
447 self.contact_edges_with(entity)
448 .filter_map(move |edge| self.get_pair_by_edge(edge))
449 }
450
451 /// Returns an iterator yielding immutable access to all entities that have a contact pair with the given entity.
452 ///
453 /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
454 /// even if the shapes themselves are not yet touching.
455 #[inline]
456 pub fn entities_colliding_with(&self, entity: Entity) -> impl Iterator<Item = Entity> + '_ {
457 self.entity_to_node
458 .get(entity)
459 .into_iter()
460 .flat_map(move |&index| {
461 self.edges
462 .neighbors(index)
463 .map(|index| *self.edges.node_weight(index).unwrap())
464 })
465 }
466
467 /// Creates a [`ContactEdge`] between two entities and adds an associated [`ContactPair`]
468 /// to the list of active pairs.
469 ///
470 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
471 ///
472 /// # Warning
473 ///
474 /// Creating a contact edge with this method will *not* trigger any collision events
475 /// or wake up the entities involved. Only use this method if you know what you are doing.
476 #[inline]
477 pub fn add_edge(&mut self, contact_edge: ContactEdge) -> Option<ContactId> {
478 self.add_edge_with(contact_edge, |_| {})
479 }
480
481 /// Creates a [`ContactEdge`] between two entities, calling the provided callback
482 /// to initialize the associated [`ContactPair`] in the list of active pairs.
483 ///
484 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
485 ///
486 /// # Warning
487 ///
488 /// Creating a contact edge with this method will *not* trigger any collision events
489 /// or wake up the entities involved. Only use this method if you know what you are doing.
490 #[inline]
491 pub fn add_edge_with<F>(
492 &mut self,
493 contact_edge: ContactEdge,
494 pair_callback: F,
495 ) -> Option<ContactId>
496 where
497 F: FnMut(&mut ContactPair),
498 {
499 let pair_key = PairKey::new(
500 contact_edge.collider1.index(),
501 contact_edge.collider2.index(),
502 );
503 self.add_edge_and_key_with(contact_edge, pair_key, pair_callback)
504 }
505
506 /// Creates a [`ContactEdge`] between two entities with the given pair key, calling the provided callback
507 /// to initialize the associated [`ContactPair`] in the list of active pairs.
508 ///
509 /// The key must be equivalent to `PairKey::new(contacts.entity1.index(), contacts.entity2.index())`.
510 ///
511 /// Returns the ID of the contact edge if it was created, or `None` if the edge already exists.
512 ///
513 /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
514 /// If the key is not available, consider using [`add_edge`](Self::add_edge) or [`add_edge_with`](Self::add_edge_with) instead.
515 ///
516 /// # Warning
517 ///
518 /// Creating a contact edge with this method will *not* trigger any collision events
519 /// or wake up the entities involved. Only use this method if you know what you are doing.
520 #[inline]
521 pub fn add_edge_and_key_with<F>(
522 &mut self,
523 contact_edge: ContactEdge,
524 pair_key: PairKey,
525 mut pair_callback: F,
526 ) -> Option<ContactId>
527 where
528 F: FnMut(&mut ContactPair),
529 {
530 // Add the pair to the pair set for fast lookup.
531 if !self.pair_set.insert(pair_key) {
532 // The pair already exists.
533 return None;
534 }
535
536 let collider1 = contact_edge.collider1;
537 let collider2 = contact_edge.collider2;
538
539 // Get the indices of the entities in the graph.
540 let index1 = self
541 .entity_to_node
542 .get_or_insert_with(collider1, || self.edges.add_node(collider1));
543 let index2 = self
544 .entity_to_node
545 .get_or_insert_with(collider2, || self.edges.add_node(collider2));
546
547 // Add the edge to the graph.
548 let edge_id = ContactId(self.edges.add_edge(index1, index2, contact_edge).0);
549
550 // Create the contact pair. Contacts are created as active.
551 let mut pair = ContactPair::new(collider1, collider2, edge_id);
552
553 // Call the pair callback to allow for custom initialization.
554 pair_callback(&mut pair);
555
556 let pair_index = self.active_pairs.len();
557 self.active_pairs.push(pair);
558
559 // Set the contact ID and pair index of the edge.
560 let edge = self.edges.edge_weight_mut(edge_id.into()).unwrap();
561 edge.id = edge_id;
562 edge.pair_index = pair_index;
563
564 Some(edge_id)
565 }
566
567 /// Removes a [`ContactEdge`] between two entites and returns its value.
568 ///
569 /// # Warning
570 ///
571 /// Removing a contact edge with this method will *not* trigger any collision events
572 /// or wake up the entities involved. Only use this method if you know what you are doing.
573 ///
574 /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
575 #[inline]
576 pub fn remove_edge(&mut self, entity1: Entity, entity2: Entity) -> Option<ContactEdge> {
577 let (Some(index1), Some(index2)) =
578 (self.entity_to_node(entity1), self.entity_to_node(entity2))
579 else {
580 return None;
581 };
582
583 // Remove the edge from the graph.
584 self.edges.find_edge(index1, index2).and_then(|edge_id| {
585 let pair_key = PairKey::new(entity1.index(), entity2.index());
586 self.remove_edge_by_id(&pair_key, edge_id.into())
587 })
588 }
589
590 /// Removes a [`ContactEdge`] based on its pair key and ID and returns its value.
591 ///
592 /// # Warning
593 ///
594 /// Removing a contact edge with this method will *not* trigger any collision events
595 /// or wake up the entities involved. Only use this method if you know what you are doing.
596 ///
597 /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
598 #[inline]
599 pub fn remove_edge_by_id(&mut self, pair_key: &PairKey, id: ContactId) -> Option<ContactEdge> {
600 // Remove the pair from the pair set.
601 self.pair_set.remove(pair_key);
602
603 // Remove the edge from the graph.
604 let edge = self.edges.remove_edge(id.into())?;
605 let edge_count = self.edges.raw_edges().len();
606
607 // Remove the contact pair from the active or sleeping pairs.
608 let pair_index = edge.pair_index;
609 let contact_pairs = if edge.is_sleeping() {
610 &mut self.sleeping_pairs
611 } else {
612 &mut self.active_pairs
613 };
614
615 let moved_index = contact_pairs.len() - 1;
616 contact_pairs.swap_remove(pair_index);
617
618 if moved_index != pair_index {
619 // Fix moved pair index.
620 let moved_contact_id = contact_pairs[pair_index].contact_id;
621 let moved_edge = self
622 .get_edge_mut_by_id(moved_contact_id)
623 .unwrap_or_else(|| {
624 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")
625 });
626 debug_assert!(moved_edge.pair_index == moved_index);
627 moved_edge.pair_index = pair_index;
628 }
629
630 Some(edge)
631 }
632
633 /// Removes the collider of the given entity from the contact graph, calling the given callback
634 /// for each [`ContactEdge`] right before it is removed.
635 ///
636 /// # Warning
637 ///
638 /// Removing a collider with this method will *not* trigger any collision events
639 /// or wake up the entities involved. Only use this method if you know what you are doing.
640 #[inline]
641 pub fn remove_collider_with<F>(&mut self, entity: Entity, mut edge_callback: F)
642 where
643 F: FnMut(&mut StableUnGraph<Entity, ContactEdge>, ContactId),
644 {
645 // Remove the entity from the entity-to-node mapping,
646 // and get the index of the node in the graph.
647 let Some(index) = self.entity_to_node.remove(entity) else {
648 return;
649 };
650
651 // Remove the entity from the graph.
652 self.edges.remove_node_with(index, |graph, edge_index| {
653 let contact_id: ContactId = edge_index.into();
654 let contact_edge = graph.edge_weight(edge_index).unwrap_or_else(|| {
655 panic!("contact edge {contact_id:?} not found in contact graph")
656 });
657 let pair_key = PairKey::new(
658 contact_edge.collider1.index(),
659 contact_edge.collider2.index(),
660 );
661 let pair_index = contact_edge.pair_index;
662 let contact_pairs = if contact_edge.is_sleeping() {
663 &mut self.sleeping_pairs
664 } else {
665 &mut self.active_pairs
666 };
667
668 edge_callback(graph, contact_id);
669
670 // Remove the contact pair from the active or sleeping pairs.
671 let moved_index = contact_pairs.len() - 1;
672 let _ = contact_pairs.swap_remove(pair_index);
673
674 // Fix moved pair index.
675 if moved_index != pair_index {
676 let moved_contact_id = contact_pairs[pair_index].contact_id;
677 let moved_edge = graph
678 .edge_weight_mut(moved_contact_id.into())
679 .unwrap_or_else(|| {
680 panic!("moved edge {moved_contact_id:?} not found in contact graph")
681 });
682 debug_assert!(moved_edge.pair_index == moved_index);
683 moved_edge.pair_index = pair_index;
684 }
685
686 // Remove the pair from the pair set.
687 self.pair_set.remove(&pair_key);
688 });
689
690 // Removing the node swapped the last node to its place,
691 // so we need to remap the entity-to-node mapping of the swapped node.
692 if let Some(swapped) = self.edges.node_weight(index).copied() {
693 let swapped_index = self
694 .entity_to_node
695 .get_mut(swapped)
696 // This should never panic.
697 .expect("swapped entity has no entity-to-node mapping");
698 *swapped_index = index;
699 }
700 }
701
702 /// Transfers touching contacts of a body from the sleeping contacts to the active contacts,
703 /// calling the given callback for each [`ContactPair`] that is moved to active contacts.
704 #[inline]
705 pub fn wake_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
706 where
707 F: FnMut(&mut ContactGraph, &ContactPair),
708 {
709 // Get the index of the entity in the graph.
710 let Some(index) = self.entity_to_node(entity) else {
711 return;
712 };
713
714 // Find all edges connected to the entity.
715 let contact_ids: Vec<ContactId> = self
716 .edges
717 .edge_weights(index)
718 .filter_map(|edge| edge.is_sleeping().then_some(edge.id))
719 .collect();
720
721 // Iterate over the edges and move sleeping contacts to active contacts.
722 for id in contact_ids {
723 let edge = self
724 .edges
725 .edge_weight_mut(id.into())
726 .expect("edge should exist");
727
728 if !edge.is_touching() {
729 // Only wake touching contacts.
730 continue;
731 }
732
733 let pair_index = edge.pair_index;
734
735 // Remove the sleeping contact pair.
736 let moved_index = self.sleeping_pairs.len() - 1;
737 let transferred_pair = self.sleeping_pairs.swap_remove(pair_index);
738
739 // Update the pair index of the edge.
740 edge.pair_index = self.active_pairs.len();
741
742 // Set the edge to active.
743 edge.flags.set(ContactEdgeFlags::SLEEPING, false);
744
745 // Call the pair callback.
746 pair_callback(self, &transferred_pair);
747
748 // Add the transferred pair to the active pairs.
749 self.active_pairs.push(transferred_pair);
750
751 // Fix moved edge.
752 if moved_index != pair_index {
753 let moved_contact_id = self.sleeping_pairs[pair_index].contact_id;
754 let moved_edge = self
755 .get_edge_mut_by_id(moved_contact_id)
756 .unwrap_or_else(|| {
757 panic!("error when waking contact pair {moved_contact_id:?} (other {id:?}) with pair index {pair_index:?}: moved edge not found in contact graph")
758 });
759 debug_assert!(moved_edge.pair_index == moved_index);
760 moved_edge.pair_index = pair_index;
761 }
762 }
763 }
764
765 /// Transfers touching contacts of a body from the active contacts to the sleeping contacts,
766 /// calling the given callback for each [`ContactPair`] that is moved to sleeping contacts.
767 #[inline]
768 pub fn sleep_entity_with<F>(&mut self, entity: Entity, mut pair_callback: F)
769 where
770 F: FnMut(&mut ContactGraph, &ContactPair),
771 {
772 // Get the index of the entity in the graph.
773 let Some(index) = self.entity_to_node(entity) else {
774 return;
775 };
776
777 // Find all edges connected to the entity.
778 let contact_ids: Vec<ContactId> = self
779 .edges
780 .edge_weights(index)
781 .filter_map(|edge| (!edge.is_sleeping()).then_some(edge.id))
782 .collect();
783
784 // Iterate over the edges and move active contacts to sleeping contacts.
785 for id in contact_ids {
786 let edge = self
787 .edges
788 .edge_weight_mut(id.into())
789 .expect("edge should exist");
790
791 if !edge.is_touching() {
792 // Only sleep touching contacts.
793 continue;
794 }
795
796 let pair_index = edge.pair_index;
797
798 // Remove the active contact pair.
799 let moved_index = self.active_pairs.len() - 1;
800 let transferred_pair = self.active_pairs.swap_remove(pair_index);
801
802 // Update the pair index of the edge.
803 edge.pair_index = self.sleeping_pairs.len();
804
805 // Set the edge to sleeping.
806 edge.flags.set(ContactEdgeFlags::SLEEPING, true);
807
808 // Call the edge callback.
809 pair_callback(self, &transferred_pair);
810
811 // Add the transferred pair to the sleeping pairs.
812 self.sleeping_pairs.push(transferred_pair);
813
814 // Fix moved edge.
815 if moved_index != pair_index {
816 let moved_contact_id = self.active_pairs[pair_index].contact_id;
817 let moved_edge = self
818 .get_edge_mut_by_id(moved_contact_id)
819 .unwrap_or_else(|| {
820 panic!("error when sleeping contact pair {moved_contact_id:?} with pair index {pair_index:?}: moved edge not found in contact graph")
821 });
822 debug_assert!(moved_edge.pair_index == moved_index);
823 moved_edge.pair_index = pair_index;
824 }
825 }
826 }
827
828 /// Clears all contact pairs and the contact graph.
829 ///
830 /// # Warning
831 ///
832 /// Clearing contact pairs with this method will *not* trigger any collision events
833 /// or wake up the entities involved. Only use this method if you know what you are doing.
834 ///
835 /// Additionally, this does *not* clear the [`ConstraintGraph`]! You should additionally
836 /// call [`ConstraintGraph::clear`].
837 ///
838 /// [`ConstraintGraph`]: crate::dynamics::solver::constraint_graph::ConstraintGraph
839 /// [`ConstraintGraph::clear`]: crate::dynamics::solver::constraint_graph::ConstraintGraph::clear
840 #[inline]
841 pub fn clear(&mut self) {
842 self.edges.clear();
843 self.active_pairs.clear();
844 self.sleeping_pairs.clear();
845 self.pair_set.clear();
846 self.entity_to_node.clear();
847 }
848}