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