avian3d/collision/contact_types/
system_param.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
use crate::data_structures::pair_key::PairKey;
use bevy::{ecs::system::SystemParam, prelude::*};

use super::{ContactGraph, ContactPair, ContactPairFlags};

/// A [`SystemParam`] for accessing and querying collision data.
///
/// This is a wrapper around the [`ContactGraph`] resource that provides a convenient API
/// for querying touching contact pairs between entities. If you need more lower-level control
/// and access to non-touching contact pairs, consider using the [`ContactGraph`] directly.
///
/// # Usage
///
/// The following methods can be used for querying collisions:
///
/// - [`get`](Self::get)
/// - [`iter`](Self::iter)
/// - [`contains`](Self::contains)
/// - [`collisions_with`](Self::collisions_with)
/// - [`entities_colliding_with`](Self::entities_colliding_with)
///
/// For example, to iterate over all collisions with a given entity:
///
/// ```
#[cfg_attr(feature = "2d", doc = "use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "use avian3d::prelude::*;")]
/// use bevy::prelude::*;
///
/// #[derive(Component)]
/// struct PressurePlate;
///
/// fn activate_pressure_plates(mut query: Query<Entity, With<PressurePlate>>, collisions: Collisions) {
///     for pressure_plate in &query {
///         // Compute the total impulse applied to the pressure plate.
///         let mut total_impulse = 0.0;
///
///         for contact_pair in collisions.collisions_with(pressure_plate) {
///             total_impulse += contact_pair.total_normal_impulse_magnitude();
///         }
///
///         if total_impulse > 5.0 {
///             println!("Pressure plate activated!");
///         }
///     }
/// }
/// ```
///
/// Contact modification and filtering should be done using [`CollisionHooks`].
/// See the documentation for more information.
///
/// [`CollisionHooks`]: crate::collision::hooks::CollisionHooks
#[derive(SystemParam)]
pub struct Collisions<'w> {
    /// The [`ContactGraph`] that stores all contact pairs.
    graph: Res<'w, ContactGraph>,
}

impl Collisions<'_> {
    /// Returns a reference to the internal [`ContactGraph`].
    ///
    /// Note that unlike [`Collisions`], which only provides touching contacts,
    /// the contact graph includes both touching and non-touching contacts.
    #[inline]
    pub fn graph(&self) -> &ContactGraph {
        &self.graph
    }

    /// Returns a touching contact pair between two entities.
    /// If the pair does not exist, `None` is returned.
    #[inline]
    pub fn get(&self, entity1: Entity, entity2: Entity) -> Option<&ContactPair> {
        self.graph.get(entity1, entity2)
    }

    /// Returns `true` if the given entities have a touching contact pair.
    #[inline]
    pub fn contains(&self, entity1: Entity, entity2: Entity) -> bool {
        self.graph.contains(entity1, entity2)
    }

    /// Returns `true` if the given pair key matches a touching contact pair.
    ///
    /// The pair key should be equivalent to `PairKey::new(entity1.index(), entity2.index())`.
    ///
    /// This method can be useful to avoid constructing a new `PairKey` when the key is already known.
    /// If the key is not available, consider using [`contains`](Self::contains) instead.
    #[inline]
    pub fn contains_key(&self, pair_key: &PairKey) -> bool {
        self.graph.contains_key(pair_key)
    }

    /// Returns an iterator yielding immutable access to all touching contact pairs.
    #[inline]
    pub fn iter(&self) -> impl Iterator<Item = &ContactPair> {
        self.graph
            .iter()
            .filter(|contacts| contacts.flags.contains(ContactPairFlags::TOUCHING))
    }

    /// Returns an iterator yielding immutable access to all touching contact pairs
    /// involving the given entity.
    #[inline]
    pub fn collisions_with(&self, entity: Entity) -> impl Iterator<Item = &ContactPair> {
        self.graph
            .collisions_with(entity)
            .filter(|contacts| contacts.is_touching())
    }

    /// Returns an iterator yielding immutable access to all entities
    /// that have a touching contact pair with the given entity.
    #[inline]
    pub fn entities_colliding_with(&self, entity: Entity) -> impl Iterator<Item = Entity> + '_ {
        // TODO: Can we do this more efficiently?
        self.collisions_with(entity).map(move |contacts| {
            if contacts.collider1 == entity {
                contacts.collider2
            } else {
                contacts.collider1
            }
        })
    }
}