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
}
})
}
}