avian3d/collision/collider/
layers.rs

1use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
2
3use bevy::prelude::*;
4
5/// A layer used for determining which entities should interact with each other.
6/// Physics layers are used heavily by [`CollisionLayers`].
7///
8/// This trait can be derived for enums with `#[derive(PhysicsLayer)]`.
9pub trait PhysicsLayer: Sized + Default {
10    /// Converts the layer to a bitmask.
11    fn to_bits(&self) -> u32;
12    /// Creates a layer bitmask with all bits set to 1.
13    fn all_bits() -> u32;
14}
15
16impl<'a, L: PhysicsLayer> PhysicsLayer for &'a L
17where
18    &'a L: Default,
19{
20    fn to_bits(&self) -> u32 {
21        L::to_bits(self)
22    }
23
24    fn all_bits() -> u32 {
25        L::all_bits()
26    }
27}
28
29/// A bitmask for layers.
30///
31/// A [`LayerMask`] can be constructed from bits directly, or from types implementing [`PhysicsLayer`].
32/// The first bit `0b0001` is reserved for the default layer, which all entities belong to by default.
33///
34/// ```
35#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
36#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
37/// #
38/// #[derive(PhysicsLayer, Clone, Copy, Debug, Default)]
39/// enum GameLayer {
40///     #[default]
41///     Default, // Layer 0 - the default layer that objects are assigned to
42///     Player,  // Layer 1
43///     Enemy,   // Layer 2
44///     Ground,  // Layer 3
45/// }
46///
47/// // The first bit is reserved for the default layer.
48/// assert_eq!(GameLayer::default().to_bits(), 1 << 0);
49///
50/// // The `GameLayer::Ground` layer is the fourth layer, so its bit value is `1 << 3`.
51/// assert_eq!(GameLayer::Ground.to_bits(), 1 << 3);
52///
53/// // Here, `GameLayer::Enemy` is automatically converted to a `LayerMask` for the comparison.
54/// assert_eq!(LayerMask(0b00100), GameLayer::Enemy);
55/// ```
56///
57/// Bitwise operations can be used to modify and combine masks:
58///
59/// ```
60#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
61#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
62/// let mask1 = LayerMask(0b0001);
63/// let mask2 = LayerMask(0b0010);
64/// assert_eq!(mask1 | mask2, LayerMask(0b0011));
65///
66/// // You can also add layers from `u32` bitmasks and compare against them directly.
67/// assert_eq!(mask1 | 0b0010, 0b0011);
68/// ```
69///
70/// Another way to use [`LayerMask`] is to define layers as constants:
71///
72/// ```
73#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
74#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
75/// // `1 << n` is bitshifting: the first layer shifted by `n` layers.
76/// pub const FIRST_LAYER: LayerMask = LayerMask(1 << 0);
77/// pub const LAST_LAYER: LayerMask = LayerMask(1 << 31);
78///
79/// // Bitwise operations for `LayerMask` unfortunately can't be const, so we need to access the `u32` values.
80/// pub const COMBINED: LayerMask = LayerMask(FIRST_LAYER.0 | LAST_LAYER.0);
81/// ```
82#[derive(Reflect, Clone, Copy, Debug, Deref, DerefMut, Eq, PartialOrd, Ord)]
83#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
84#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
85#[reflect(Debug, PartialEq)]
86pub struct LayerMask(pub u32);
87
88impl From<u32> for LayerMask {
89    fn from(layer: u32) -> Self {
90        Self(layer)
91    }
92}
93
94impl<L: PhysicsLayer> From<L> for LayerMask {
95    fn from(layer: L) -> Self {
96        LayerMask(layer.to_bits())
97    }
98}
99
100impl<L: Into<LayerMask>, const N: usize> From<[L; N]> for LayerMask {
101    fn from(value: [L; N]) -> Self {
102        let mut bits = 0;
103
104        for layer in value.into_iter().map(|l| {
105            let layers: LayerMask = l.into();
106            layers
107        }) {
108            bits |= layer.0;
109        }
110
111        LayerMask(bits)
112    }
113}
114
115impl LayerMask {
116    /// Contains all layers.
117    pub const ALL: Self = Self(0xffff_ffff);
118    /// Contains no layers.
119    pub const NONE: Self = Self(0);
120    /// Contains the default layer.
121    pub const DEFAULT: Self = Self(1);
122
123    /// Adds the given `layers` to `self`.
124    ///
125    /// # Example
126    ///
127    /// ```
128    #[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
129    #[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
130    /// let mut layers = LayerMask(0b1010);
131    ///
132    /// // These are equivalent
133    /// layers.add(0b0001);
134    /// layers |= 0b0001;
135    ///
136    /// assert_eq!(layers, 0b1011);
137    /// ```
138    pub fn add(&mut self, layers: impl Into<Self>) {
139        let layers: LayerMask = layers.into();
140        *self |= layers;
141    }
142
143    /// Removes the given `layers` from `self`.
144    ///
145    /// # Example
146    ///
147    /// ```
148    #[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
149    #[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
150    /// let mut layers = LayerMask(0b1010);
151    ///
152    /// // These are equivalent
153    /// layers.remove(0b0010);
154    /// layers &= !0b0010;
155    ///
156    /// assert_eq!(layers, 0b1000);
157    /// ```
158    pub fn remove(&mut self, layers: impl Into<Self>) {
159        let layers: LayerMask = layers.into();
160        *self &= !layers;
161    }
162
163    /// Returns `true` if `self` contains all of the given `layers`.
164    ///
165    /// # Example
166    ///
167    /// ```
168    #[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
169    #[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
170    /// let mut layers = LayerMask(0b1010);
171    ///
172    /// // These are equivalent
173    /// assert!(layers.has_all(0b1010));
174    /// assert!((layers & 0b1010) != 0);
175    ///
176    /// assert!(!layers.has_all(0b0100));
177    /// assert!((layers & 0b0100) == 0);
178    /// ```
179    #[doc(alias = "contains_all")]
180    pub fn has_all(self, layers: impl Into<Self>) -> bool {
181        let layers: LayerMask = layers.into();
182        (self & layers) != 0
183    }
184}
185
186impl<L: Into<LayerMask> + Copy> PartialEq<L> for LayerMask {
187    fn eq(&self, other: &L) -> bool {
188        let other: Self = (*other).into();
189        self.0 == other.0
190    }
191}
192
193impl<L: Into<LayerMask>> BitAnd<L> for LayerMask {
194    type Output = Self;
195
196    fn bitand(self, rhs: L) -> Self::Output {
197        Self(self.0 & rhs.into().0)
198    }
199}
200
201impl<L: Into<LayerMask>> BitAndAssign<L> for LayerMask {
202    fn bitand_assign(&mut self, rhs: L) {
203        self.0 = self.0 & rhs.into().0;
204    }
205}
206
207impl<L: Into<LayerMask>> BitOr<L> for LayerMask {
208    type Output = Self;
209
210    fn bitor(self, rhs: L) -> Self::Output {
211        Self(self.0 | rhs.into().0)
212    }
213}
214
215impl<L: Into<LayerMask>> BitOrAssign<L> for LayerMask {
216    fn bitor_assign(&mut self, rhs: L) {
217        self.0 = self.0 | rhs.into().0;
218    }
219}
220
221impl<L: Into<LayerMask>> BitXor<L> for LayerMask {
222    type Output = Self;
223
224    fn bitxor(self, rhs: L) -> Self::Output {
225        Self(self.0 ^ rhs.into().0)
226    }
227}
228
229impl<L: Into<LayerMask>> BitXorAssign<L> for LayerMask {
230    fn bitxor_assign(&mut self, rhs: L) {
231        self.0 = self.0 ^ rhs.into().0;
232    }
233}
234
235impl Not for LayerMask {
236    type Output = Self;
237
238    fn not(self) -> Self::Output {
239        Self(!self.0)
240    }
241}
242
243/// Defines the collision layers of a collider using *memberships* and *filters*.
244///
245/// **Memberships** indicate what layers the collider is a part of.\
246/// **Filters** indicate what layers the collider can interact with.
247///
248/// Two colliders `A` and `B` can interact if and only if:
249///
250/// - The memberships of `A` contain a layer that is also in the filters of `B`
251/// - The memberships of `B` contain a layer that is also in the filters of `A`
252///
253/// The memberships and filters are stored as [`LayerMask`]s, which represent [bitmasks] for layers.
254/// The first bit `0b0001` is reserved for the default layer, which all entities belong to by default.
255///
256/// By default, colliders have all filters and can interact with any layer.
257///
258/// [bitmasks]: https://en.wikipedia.org/wiki/Mask_(computing)
259///
260/// # Creation
261///
262/// Collision layers store memberships and filters using [`LayerMask`]s. A [`LayerMask`] can be created using
263/// bitmasks, or by creating an enum that implements [`PhysicsLayer`].
264///
265/// Many [`CollisionLayers`] methods can take any type that implements `Into<LayerMask>`.
266/// For example, you can use bitmasks with [`CollisionLayers::new`]:
267///
268/// ```
269#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
270#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
271/// #
272/// // Belongs to the second layer and interacts with colliders
273/// // on the first, second, and third layer.
274/// let layers = CollisionLayers::new(0b00010, 0b0111);
275/// ```
276///
277/// You can also use an enum that implements [`PhysicsLayer`]:
278///
279/// ```
280#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
281#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
282/// #
283/// #[derive(PhysicsLayer, Default)]
284/// enum GameLayer {
285///     #[default]
286///     Default, // Layer 0 - the default layer that objects are assigned to
287///     Player,  // Layer 1
288///     Enemy,   // Layer 2
289///     Ground,  // Layer 3
290/// }
291///
292/// // Player collides with enemies and the ground, but not with other players
293/// let layers = CollisionLayers::new(
294///     GameLayer::Player,
295///     [GameLayer::Default, GameLayer::Enemy, GameLayer::Ground],
296/// );
297/// ```
298///
299/// You can also use [`LayerMask`] directly:
300///
301/// ```
302#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
303#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
304/// #
305/// // Belongs to the first layer and interacts with all layers.
306/// let layers = CollisionLayers::new(LayerMask(0b0001), LayerMask::ALL);
307/// ```
308///
309/// Layers can also be defined using constants and bitwise operations:
310///
311/// ```
312#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
313#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
314/// # use bevy::prelude::Commands;
315/// #
316/// // `1 << n` is bitshifting: the first layer shifted by `n` layers.
317/// pub const FIRST_LAYER: u32 = 1 << 0; // Note: this is the default layer.
318/// pub const SECOND_LAYER: u32 = 1 << 1;
319/// pub const LAST_LAYER: u32 = 1 << 31;
320///
321/// fn spawn(mut commands: Commands) {
322///     // This collider belongs to the first two layers and can interact with the last layer.
323///     commands.spawn((
324#[cfg_attr(feature = "2d", doc = "        Collider::circle(0.5),")]
325#[cfg_attr(feature = "3d", doc = "        Collider::sphere(0.5),")]
326///         CollisionLayers::from_bits(FIRST_LAYER | SECOND_LAYER, LAST_LAYER),
327///     ));
328/// }
329/// ```
330///
331/// # Modifying Layers
332///
333/// Existing [`CollisionLayers`] can be modified by simply accessing the `memberships` and `filters`
334/// and changing their [`LayerMask`]s.
335///
336/// ```
337#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
338#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
339/// let mut layers = CollisionLayers::new(0b0010, 0b1011);
340///
341/// // Add memberships (these are equivalent)
342/// layers.memberships.add(0b0001);
343/// layers.memberships |= 0b0001;
344///
345/// assert_eq!(layers.memberships, 0b0011);
346///
347/// // Remove filters
348/// layers.filters.remove(0b0001);
349/// layers.filters &= !0b0001;
350///
351/// assert_eq!(layers.filters, 0b1010);
352///
353/// // Check if layers are contained
354/// assert!(layers.memberships.has_all(0b0011));
355/// assert!((layers.memberships & 0b0011) != 0);
356/// ```
357#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq, Eq)]
358#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
359#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
360#[reflect(Debug, Component, PartialEq)]
361pub struct CollisionLayers {
362    /// The layers that an entity belongs to.
363    #[doc(alias = "groups", alias = "layers")]
364    pub memberships: LayerMask,
365    /// The layers that an entity can interact with.
366    #[doc(alias = "masks", alias = "layer_mask")]
367    pub filters: LayerMask,
368}
369
370impl CollisionLayers {
371    /// Contains the default layer and all filters.
372    pub const DEFAULT: Self = Self {
373        memberships: LayerMask::DEFAULT,
374        filters: LayerMask::ALL,
375    };
376
377    /// Contains all memberships and filters.
378    pub const ALL: Self = Self {
379        memberships: LayerMask::ALL,
380        filters: LayerMask::ALL,
381    };
382
383    /// Contains no memberships and no filters.
384    pub const NONE: Self = Self {
385        memberships: LayerMask::NONE,
386        filters: LayerMask::NONE,
387    };
388
389    /// Contains all memberships but no filters.
390    pub const ALL_MEMBERSHIPS: Self = Self {
391        memberships: LayerMask::ALL,
392        filters: LayerMask::NONE,
393    };
394
395    /// Contains all filters but no memberships.
396    pub const ALL_FILTERS: Self = Self {
397        memberships: LayerMask::NONE,
398        filters: LayerMask::ALL,
399    };
400
401    /// Creates a new [`CollisionLayers`] configuration with the given collision memberships and filters.
402    pub fn new(memberships: impl Into<LayerMask>, filters: impl Into<LayerMask>) -> Self {
403        Self {
404            memberships: memberships.into(),
405            filters: filters.into(),
406        }
407    }
408
409    /// Creates a new [`CollisionLayers`] configuration using bits.
410    ///
411    /// There is one bit per group and mask, so there are a total of 32 layers.
412    /// For example, if an entity is a part of the layers `[0, 1, 3]` and can interact with the layers `[1, 2]`,
413    /// the memberships in bits would be `0b01011` while the filters would be `0b00110`.
414    pub const fn from_bits(memberships: u32, filters: u32) -> Self {
415        Self {
416            memberships: LayerMask(memberships),
417            filters: LayerMask(filters),
418        }
419    }
420
421    /// Returns true if an entity with this [`CollisionLayers`] configuration
422    /// can interact with an entity with the `other` [`CollisionLayers`] configuration.
423    pub fn interacts_with(self, other: Self) -> bool {
424        (self.memberships & other.filters) != LayerMask::NONE
425            && (other.memberships & self.filters) != LayerMask::NONE
426    }
427}
428
429impl Default for CollisionLayers {
430    fn default() -> Self {
431        CollisionLayers::DEFAULT
432    }
433}
434
435#[cfg(test)]
436mod tests {
437    use crate::prelude::*;
438
439    #[derive(PhysicsLayer, Default)]
440    enum GameLayer {
441        #[default]
442        Default,
443        Player,
444        Enemy,
445        Ground,
446    }
447
448    #[test]
449    fn creation() {
450        let with_bitmask = CollisionLayers::new(0b00100, 0b01011);
451        let with_enum = CollisionLayers::new(
452            GameLayer::Enemy,
453            [GameLayer::Default, GameLayer::Player, GameLayer::Ground],
454        );
455        let with_layers =
456            CollisionLayers::new(LayerMask::from(GameLayer::Enemy), LayerMask(0b01011));
457
458        assert_eq!(with_bitmask, with_enum);
459        assert_eq!(with_bitmask, with_layers);
460
461        assert!(with_bitmask.memberships.has_all(GameLayer::Enemy));
462        assert!(!with_bitmask.memberships.has_all(GameLayer::Player));
463
464        assert!(with_bitmask
465            .filters
466            .has_all([GameLayer::Player, GameLayer::Ground]));
467        assert!(!with_bitmask.filters.has_all(GameLayer::Enemy));
468    }
469}