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 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
use bevy::prelude::*;
/// A layer used for determining which entities should interact with each other.
/// Physics layers are used heavily by [`CollisionLayers`].
///
/// This trait can be derived for enums with `#[derive(PhysicsLayer)]`.
pub trait PhysicsLayer: Sized {
/// Converts the layer to a bitmask.
fn to_bits(&self) -> u32;
/// Creates a layer bitmask with all bits set to 1.
fn all_bits() -> u32;
}
impl<L: PhysicsLayer> PhysicsLayer for &L {
fn to_bits(&self) -> u32 {
L::to_bits(self)
}
fn all_bits() -> u32 {
L::all_bits()
}
}
/// Defines the collision layers of a collider using *groups* and *masks*.
///
/// **Groups** indicate what layers the collider is a part of.\
/// **Masks** indicate what layers the collider can interact with.
///
/// Two colliders `A` and `B` can interact if and only if:
///
/// - The groups of `A` contain a layer that is also in the masks of `B`
/// - The groups of `B` contain a layer that is also in the masks of `A`
///
/// Colliders without this component can be considered as having all groups and masks, and they can
/// interact with everything that belongs on any layer.
///
/// ## Creation
///
/// The easiest way to build a [`CollisionLayers`] configuration is to use the [`CollisionLayers::new()`](#method.new) method
/// that takes in a list of groups and masks. Additional groups and masks can be added and removed by calling methods like
/// [`add_groups`](#method.add_groups), [`add_masks`](#method.add_masks), [`remove_groups`](#method.remove_groups) and
/// [`remove_masks`](#method.remove_masks).
///
/// These methods require the layers to implement [`PhysicsLayer`]. The easiest way to define the physics layers is to
/// create an enum with `#[derive(PhysicsLayer)]`.
///
/// Internally, the groups and masks are represented as bitmasks, so you can also use [`CollisionLayers::from_bits()`](#method.from_bits)
/// to create collision layers.
///
/// ## Example
///
/// ```
/// use bevy::prelude::*;
/// # #[cfg(feature = "2d")]
/// # use bevy_xpbd_2d::prelude::*;
/// # #[cfg(feature = "3d")]
/// use bevy_xpbd_3d::prelude::*;
///
/// #[derive(PhysicsLayer)]
/// enum Layer {
/// Player,
/// Enemy,
/// Ground,
/// }
///
/// fn spawn(mut commands: Commands) {
/// commands.spawn((
/// Collider::ball(0.5),
/// // Player collides with enemies and the ground, but not with other players
/// CollisionLayers::new([Layer::Player], [Layer::Enemy, Layer::Ground])
/// ));
/// }
/// ```
#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq)]
#[reflect(Component)]
pub struct CollisionLayers {
groups: u32,
masks: u32,
}
impl CollisionLayers {
/// Creates a new [`CollisionLayers`] configuration with the given collision groups and masks.
pub fn new<L: PhysicsLayer>(
groups: impl IntoIterator<Item = L>,
masks: impl IntoIterator<Item = L>,
) -> Self {
Self::none().add_groups(groups).add_masks(masks)
}
/// Contains all groups and masks.
pub fn all<L: PhysicsLayer>() -> Self {
Self::from_bits(L::all_bits(), L::all_bits())
}
/// Contains all groups but no masks.
pub fn all_groups<L: PhysicsLayer>() -> Self {
Self::from_bits(L::all_bits(), 0)
}
/// Contains all masks but no groups.
pub fn all_masks<L: PhysicsLayer>() -> Self {
Self::from_bits(0, L::all_bits())
}
/// Contains no masks or groups.
pub const fn none() -> Self {
Self::from_bits(0, 0)
}
/// Creates a new [`CollisionLayers`] using bits.
///
/// There is one bit per group and mask, so there are a total of 32 layers.
/// For example, if an entity is a part of the layers `[0, 1, 3]` and can interact with the layers `[1, 2]`,
/// the groups in bits would be `0b01011` while the masks would be `0b00110`.
pub const fn from_bits(groups: u32, masks: u32) -> Self {
Self { groups, masks }
}
/// Returns true if an entity with this [`CollisionLayers`] configuration
/// can interact with an entity with the `other` [`CollisionLayers`] configuration.
pub fn interacts_with(self, other: Self) -> bool {
(self.groups & other.masks) != 0 && (other.groups & self.masks) != 0
}
/// Returns true if the given layer is contained in `groups`.
pub fn contains_group(self, layer: impl PhysicsLayer) -> bool {
(self.groups & layer.to_bits()) != 0
}
/// Adds the given layer into `groups`.
pub fn add_group(mut self, layer: impl PhysicsLayer) -> Self {
self.groups |= layer.to_bits();
self
}
/// Adds the given layers into `groups`.
pub fn add_groups(mut self, layers: impl IntoIterator<Item = impl PhysicsLayer>) -> Self {
for layer in layers.into_iter().map(|l| l.to_bits()) {
self.groups |= layer;
}
self
}
/// Removes the given layer from `groups`.
pub fn remove_group(mut self, layer: impl PhysicsLayer) -> Self {
self.groups &= !layer.to_bits();
self
}
/// Removes the given layers from `groups`.
pub fn remove_groups(mut self, layers: impl IntoIterator<Item = impl PhysicsLayer>) -> Self {
for layer in layers.into_iter().map(|l| l.to_bits()) {
self.groups &= !layer;
}
self
}
/// Returns true if the given layer is contained in `masks`.
pub fn contains_mask(self, layer: impl PhysicsLayer) -> bool {
(self.masks & layer.to_bits()) != 0
}
/// Adds the given layer into `masks`.
pub fn add_mask(mut self, layer: impl PhysicsLayer) -> Self {
self.masks |= layer.to_bits();
self
}
/// Adds the given layers in `masks`.
pub fn add_masks(mut self, layers: impl IntoIterator<Item = impl PhysicsLayer>) -> Self {
for layer in layers.into_iter().map(|l| l.to_bits()) {
self.masks |= layer;
}
self
}
/// Removes the given layer from `masks`.
pub fn remove_mask(mut self, layer: impl PhysicsLayer) -> Self {
self.masks &= !layer.to_bits();
self
}
/// Removes the given layers from `masks`.
pub fn remove_masks(mut self, layers: impl IntoIterator<Item = impl PhysicsLayer>) -> Self {
for layer in layers.into_iter().map(|l| l.to_bits()) {
self.masks &= !layer;
}
self
}
/// Returns the `groups` bitmask.
pub fn groups_bits(self) -> u32 {
self.groups
}
/// Returns the `masks` bitmask.
pub fn masks_bits(self) -> u32 {
self.masks
}
}
impl Default for CollisionLayers {
fn default() -> Self {
Self {
groups: 0xffff_ffff,
masks: 0xffff_ffff,
}
}
}