avian3d/collision/contact_types/
contact_graph.rs

1use crate::data_structures::{
2    graph::{EdgeWeightsMut, NodeIndex, UnGraph},
3    pair_key::PairKey,
4    sparse_secondary_map::SparseSecondaryEntityMap,
5};
6#[expect(unused_imports)]
7use crate::prelude::*;
8use bevy::{platform::collections::HashSet, prelude::*};
9
10use super::{ContactPair, ContactPairFlags};
11
12/// A resource that stores all contact pairs in the physics world
13/// in an [undirected graph](UnGraph).
14///
15/// Contact pairs exist between [colliders](Collider) that have intersecting [AABBs](ColliderAabb),
16/// even if the shapes themselves are not yet touching.
17///
18/// For a simpler API that only provides touching contacts, consider using the [`Collisions`]
19/// system parameter.
20///
21/// # Usage
22///
23/// The following methods can be used for querying collisions:
24///
25/// - [`get`](Self::get) and [`get_mut`](Self::get_mut)
26/// - [`iter`](Self::iter) and [`iter_mut`](Self::iter_mut)
27/// - [`contains`](Self::contains)
28/// - [`collisions_with`](Self::collisions_with) and
29///   [`collisions_with_mut`](Self::collisions_with_mut)
30/// - [`entities_colliding_with`](Self::entities_colliding_with)
31///
32/// For example, to iterate over all collisions with a given entity:
33///
34/// ```
35#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
36#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
37/// use bevy::prelude::*;
38///
39/// #[derive(Component)]
40/// struct PressurePlate;
41///
42/// fn activate_pressure_plates(mut query: Query<Entity, With<PressurePlate>>, contact_graph: Res<ContactGraph>) {
43///     for pressure_plate in &query {
44///         // Compute the total impulse applied to the pressure plate.
45///         let mut total_impulse = 0.0;
46///
47///         for contact_pair in contact_graph.collisions_with(pressure_plate) {
48///             total_impulse += contact_pair.total_normal_impulse_magnitude();
49///         }
50///
51///         if total_impulse > 5.0 {
52///             println!("Pressure plate activated!");
53///         }
54///     }
55/// }
56/// ```
57///
58/// While mutable access is allowed, contact modification and filtering should typically
59/// be done using [`CollisionHooks`]. See the documentation for more information.
60///
61/// # Warning
62///
63/// For users, this resource is primarily for querying and reading collision data.
64///
65/// Directly adding, modifying, or removing contact pairs using this resource will *not* trigger any collision events,
66/// wake up the entities involved, or perform any other cleanup. Only make structural modifications if you know what you are doing.
67///
68/// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
69#[derive(Resource, Clone, Debug, Default)]
70pub struct ContactGraph {
71    // TODO: We could have a separate intersection graph for sensors.
72    /// The internal undirected graph where nodes are entities and edges are contact pairs.
73    pub internal: UnGraph<Entity, ContactPair>,
74
75    /// A set of all contact pairs for fast lookup.
76    ///
77    /// The [`PairKey`] is a unique pair of entity indices, sorted in ascending order,
78    /// concatenated into a single `u64` key.
79    ///
80    /// Two entities have a contact pair if they have intersecting AABBs.
81    pub(crate) pair_set: HashSet<PairKey>,
82
83    /// A map from entities to their corresponding node indices in the contact graph.
84    entity_to_node: SparseSecondaryEntityMap<NodeIndex>,
85}
86
87impl ContactGraph {
88    /// Returns the contact pair between two entities.
89    /// If the pair does not exist, `None` is returned.
90    ///
91    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
92    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
93    #[inline]
94    pub fn get(&self, entity1: Entity, entity2: Entity) -> Option<&ContactPair> {
95        let (Some(&index1), Some(&index2)) = (
96            self.entity_to_node.get(entity1),
97            self.entity_to_node.get(entity2),
98        ) else {
99            return None;
100        };
101
102        self.internal
103            .find_edge(index1, index2)
104            .and_then(|edge| self.internal.edge_weight(edge))
105    }
106
107    /// Returns a mutable reference to the contact pair between two entities.
108    /// If the pair does not exist, `None` is returned.
109    ///
110    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect.
111    /// Use [`ContactPair::is_touching`] to determine if the actual collider shapes are touching.
112    #[inline]
113    pub fn get_mut(&mut self, entity1: Entity, entity2: Entity) -> Option<&mut ContactPair> {
114        let (Some(&index1), Some(&index2)) = (
115            self.entity_to_node.get(entity1),
116            self.entity_to_node.get(entity2),
117        ) else {
118            return None;
119        };
120
121        self.internal
122            .find_edge(index1, index2)
123            .and_then(|edge| self.internal.edge_weight_mut(edge))
124    }
125
126    /// Returns `true` if the given entities have a contact pair.
127    ///
128    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
129    /// even if the shapes themselves are not yet touching.
130    #[inline]
131    pub fn contains(&self, entity1: Entity, entity2: Entity) -> bool {
132        self.contains_key(&PairKey::new(entity1.index(), entity2.index()))
133    }
134
135    /// Returns `true` if the given pair key is in the contact graph.
136    ///
137    /// The pair key should be equivalent to `PairKey::new(entity1.index(), entity2.index())`.
138    ///
139    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
140    /// If the key is not available, consider using [`contains`](Self::contains) instead.
141    #[inline]
142    pub fn contains_key(&self, pair_key: &PairKey) -> bool {
143        self.pair_set.contains(pair_key)
144    }
145
146    /// Returns an iterator yielding immutable access to all contact pairs.
147    ///
148    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
149    /// even if the shapes themselves are not yet touching.
150    ///
151    /// If you only want touching contacts, use [`iter_touching`](Self::iter_touching) instead.
152    #[inline]
153    pub fn iter(&self) -> impl Iterator<Item = &ContactPair> {
154        self.internal.all_edge_weights()
155    }
156
157    /// Returns an iterator yielding immutable access to all contact pairs that are currently touching.
158    ///
159    /// This is a subset of [`iter`](Self::iter) that only includes pairs where the colliders are touching.
160    #[inline]
161    pub fn iter_touching(&self) -> impl Iterator<Item = &ContactPair> {
162        self.internal
163            .all_edge_weights()
164            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
165    }
166
167    /// Returns a iterator yielding mutable access to all contact pairs.
168    ///
169    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
170    /// even if the shapes themselves are not yet touching.
171    ///
172    /// If you only want touching contacts, use [`iter_touching_mut`](Self::iter_touching_mut) instead.
173    #[inline]
174    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
175        self.internal.all_edge_weights_mut()
176    }
177
178    /// Returns a iterator yielding mutable access to all contact pairs that are currently touching.
179    ///
180    /// This is a subset of [`iter_mut`](Self::iter_mut) that only includes pairs where the colliders are touching.
181    #[inline]
182    pub fn iter_touching_mut(&mut self) -> impl Iterator<Item = &mut ContactPair> {
183        self.internal
184            .all_edge_weights_mut()
185            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
186    }
187
188    /// Returns an iterator yielding immutable access to all contact pairs involving the given entity.
189    ///
190    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
191    /// even if the shapes themselves are not yet touching.
192    ///
193    /// Use [`ContactPair::is_touching`](ContactPair::is_touching) to determine if the actual collider shapes are touching.
194    #[inline]
195    pub fn collisions_with(&self, entity: Entity) -> impl Iterator<Item = &ContactPair> {
196        self.entity_to_node
197            .get(entity)
198            .into_iter()
199            .flat_map(move |&index| self.internal.edge_weights(index))
200    }
201
202    /// Returns an iterator yielding mutable access to all contact pairs involving the given entity.
203    ///
204    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
205    /// even if the shapes themselves are not yet touching.
206    ///
207    /// Use [`ContactPair::is_touching`](ContactPair::is_touching) to determine if the actual collider shapes are touching.
208    #[inline]
209    pub fn collisions_with_mut(
210        &mut self,
211        entity: Entity,
212    ) -> impl Iterator<Item = &mut ContactPair> {
213        if let Some(&index) = self.entity_to_node.get(entity) {
214            self.internal.edge_weights_mut(index)
215        } else {
216            EdgeWeightsMut {
217                graph: &mut self.internal,
218                incoming_edge: None,
219                outgoing_edge: None,
220            }
221        }
222    }
223
224    /// Returns an iterator yielding immutable access to all entities that have a contact pair with the given entity.
225    ///
226    /// A contact pair exists between two entities if their [`ColliderAabb`]s intersect,
227    /// even if the shapes themselves are not yet touching.
228    #[inline]
229    pub fn entities_colliding_with(&self, entity: Entity) -> impl Iterator<Item = Entity> + '_ {
230        self.entity_to_node
231            .get(entity)
232            .into_iter()
233            .flat_map(move |&index| {
234                self.internal
235                    .neighbors(index)
236                    .map(|index| *self.internal.node_weight(index).unwrap())
237            })
238    }
239
240    /// Creates a contact pair between two entities.
241    ///
242    /// If a pair with the same entities already exists, this will do nothing.
243    ///
244    /// # Warning
245    ///
246    /// Creating a collision pair with this method will *not* trigger any collision events
247    /// or wake up the entities involved. Only use this method if you know what you are doing.
248    #[inline]
249    pub fn add_pair(&mut self, contacts: ContactPair) {
250        let pair_key = PairKey::new(contacts.collider1.index(), contacts.collider2.index());
251        self.add_pair_with_key(contacts, pair_key);
252    }
253
254    /// Creates a contact pair between two entities with the given pair key.
255    ///
256    /// The key must be equivalent to `PairKey::new(contacts.entity1.index(), contacts.entity2.index())`.
257    ///
258    /// If a pair with the same entities already exists, this will do nothing.
259    ///
260    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
261    /// If the key is not available, consider using [`add_pair`](Self::add_pair) instead.
262    ///
263    /// # Warning
264    ///
265    /// Creating a collision pair with this method will *not* trigger any collision events
266    /// or wake up the entities involved. Only use this method if you know what you are doing.
267    #[inline]
268    pub fn add_pair_with_key(&mut self, contacts: ContactPair, pair_key: PairKey) {
269        // Add the pair to the pair set for fast lookup.
270        if !self.pair_set.insert(pair_key) {
271            // The pair already exists.
272            return;
273        }
274
275        // Get the indices of the entities in the graph.
276        let index1 = self
277            .entity_to_node
278            .get_or_insert_with(contacts.collider1, || {
279                self.internal.add_node(contacts.collider1)
280            });
281        let index2 = self
282            .entity_to_node
283            .get_or_insert_with(contacts.collider2, || {
284                self.internal.add_node(contacts.collider2)
285            });
286
287        // Add the edge to the graph.
288        self.internal.add_edge(index1, index2, contacts);
289    }
290
291    /// Inserts a contact pair between two entities.
292    ///
293    /// If a pair with the same entities already exists, it will be overwritten.
294    ///
295    /// # Warning
296    ///
297    /// Inserting a collision pair with this method will *not* trigger any collision events
298    /// or wake up the entities involved. Only use this method if you know what you are doing.
299    #[inline]
300    pub fn insert_pair(&mut self, contacts: ContactPair) {
301        let pair_key = PairKey::new(contacts.collider1.index(), contacts.collider2.index());
302        self.insert_pair_with_key(contacts, pair_key);
303    }
304
305    /// Inserts a contact pair between two entities with the given pair key.
306    ///
307    /// The key must be equivalent to `PairKey::new(contacts.entity1.index(), contacts.entity2.index())`.
308    ///
309    /// If a pair with the same entities already exists, it will be overwritten.
310    ///
311    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
312    /// If the key is not available, consider using [`insert_pair`](Self::insert_pair) instead.
313    ///
314    /// # Warning
315    ///
316    /// Inserting a collision pair with this method will *not* trigger any collision events
317    /// or wake up the entities involved. Only use this method if you know what you are doing.
318    #[inline]
319    pub fn insert_pair_with_key(&mut self, contacts: ContactPair, pair_key: PairKey) {
320        // Add the pair to the pair set for fast lookup.
321        self.pair_set.insert(pair_key);
322
323        // Get the indices of the entities in the graph.
324        let index1 = self
325            .entity_to_node
326            .get_or_insert_with(contacts.collider1, || {
327                self.internal.add_node(contacts.collider1)
328            });
329        let index2 = self
330            .entity_to_node
331            .get_or_insert_with(contacts.collider2, || {
332                self.internal.add_node(contacts.collider2)
333            });
334
335        // Update the edge in the graph.
336        self.internal.update_edge(index1, index2, contacts);
337    }
338
339    /// Removes a contact pair between two entites and returns its value.
340    ///
341    /// # Warning
342    ///
343    /// Removing a collision pair with this method will *not* trigger any collision events
344    /// or wake up the entities involved. Only use this method if you know what you are doing.
345    ///
346    /// For filtering and modifying collisions, consider using [`CollisionHooks`] instead.
347    #[inline]
348    pub fn remove_pair(&mut self, entity1: Entity, entity2: Entity) -> Option<ContactPair> {
349        let (Some(&index1), Some(&index2)) = (
350            self.entity_to_node.get(entity1),
351            self.entity_to_node.get(entity2),
352        ) else {
353            return None;
354        };
355
356        // Remove the pair from the pair set.
357        self.pair_set
358            .remove(&PairKey::new(entity1.index(), entity2.index()));
359
360        // Remove the edge from the graph.
361        self.internal
362            .find_edge(index1, index2)
363            .and_then(|edge| self.internal.remove_edge(edge))
364    }
365
366    /// Removes the collider of the given entity from the contact graph,
367    /// calling the given callback for each contact pair that is removed in the process.
368    ///
369    /// # Warning
370    ///
371    /// Removing a collider with this method will *not* trigger any collision events
372    /// or wake up the entities involved. Only use this method if you know what you are doing.
373    #[inline]
374    pub fn remove_collider_with<F>(&mut self, entity: Entity, mut pair_callback: F)
375    where
376        F: FnMut(ContactPair),
377    {
378        // Remove the entity from the entity-to-node mapping,
379        // and get the index of the node in the graph.
380        let Some(index) = self.entity_to_node.remove(entity) else {
381            return;
382        };
383
384        // Remove the entity from the graph.
385        self.internal.remove_node_with(index, |contacts| {
386            let pair_key = PairKey::new(contacts.collider1.index(), contacts.collider2.index());
387
388            pair_callback(contacts);
389
390            // Remove the pair from the pair set.
391            self.pair_set.remove(&pair_key);
392        });
393
394        // Removing the node swapped the last node to its place,
395        // so we need to remap the entity-to-node mapping of the swapped node.
396        if let Some(swapped) = self.internal.node_weight(index).copied() {
397            let swapped_index = self
398                .entity_to_node
399                .get_mut(swapped)
400                // This should never panic.
401                .expect("swapped entity has no entity-to-node mapping");
402            *swapped_index = index;
403        }
404    }
405}