use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not};
use bevy::prelude::*;
pub trait PhysicsLayer: Sized + Default {
fn to_bits(&self) -> u32;
fn all_bits() -> u32;
}
impl<'a, L: PhysicsLayer> PhysicsLayer for &'a L
where
&'a L: Default,
{
fn to_bits(&self) -> u32 {
L::to_bits(self)
}
fn all_bits() -> u32 {
L::all_bits()
}
}
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[derive(Reflect, Clone, Copy, Debug, Deref, DerefMut, Eq, PartialOrd, Ord)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, PartialEq)]
pub struct LayerMask(pub u32);
impl From<u32> for LayerMask {
fn from(layer: u32) -> Self {
Self(layer)
}
}
impl<L: PhysicsLayer> From<L> for LayerMask {
fn from(layer: L) -> Self {
LayerMask(layer.to_bits())
}
}
impl<L: Into<LayerMask>, const N: usize> From<[L; N]> for LayerMask {
fn from(value: [L; N]) -> Self {
let mut bits = 0;
for layer in value.into_iter().map(|l| {
let layers: LayerMask = l.into();
layers
}) {
bits |= layer.0;
}
LayerMask(bits)
}
}
impl LayerMask {
pub const ALL: Self = Self(0xffff_ffff);
pub const NONE: Self = Self(0);
pub const DEFAULT: Self = Self(1);
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
pub fn add(&mut self, layers: impl Into<Self>) {
let layers: LayerMask = layers.into();
*self |= layers;
}
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
pub fn remove(&mut self, layers: impl Into<Self>) {
let layers: LayerMask = layers.into();
*self &= !layers;
}
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[doc(alias = "contains_all")]
pub fn has_all(self, layers: impl Into<Self>) -> bool {
let layers: LayerMask = layers.into();
(self & layers) != 0
}
}
impl<L: Into<LayerMask> + Copy> PartialEq<L> for LayerMask {
fn eq(&self, other: &L) -> bool {
let other: Self = (*other).into();
self.0 == other.0
}
}
impl<L: Into<LayerMask>> BitAnd<L> for LayerMask {
type Output = Self;
fn bitand(self, rhs: L) -> Self::Output {
Self(self.0 & rhs.into().0)
}
}
impl<L: Into<LayerMask>> BitAndAssign<L> for LayerMask {
fn bitand_assign(&mut self, rhs: L) {
self.0 = self.0 & rhs.into().0;
}
}
impl<L: Into<LayerMask>> BitOr<L> for LayerMask {
type Output = Self;
fn bitor(self, rhs: L) -> Self::Output {
Self(self.0 | rhs.into().0)
}
}
impl<L: Into<LayerMask>> BitOrAssign<L> for LayerMask {
fn bitor_assign(&mut self, rhs: L) {
self.0 = self.0 | rhs.into().0;
}
}
impl<L: Into<LayerMask>> BitXor<L> for LayerMask {
type Output = Self;
fn bitxor(self, rhs: L) -> Self::Output {
Self(self.0 ^ rhs.into().0)
}
}
impl<L: Into<LayerMask>> BitXorAssign<L> for LayerMask {
fn bitxor_assign(&mut self, rhs: L) {
self.0 = self.0 ^ rhs.into().0;
}
}
impl Not for LayerMask {
type Output = Self;
fn not(self) -> Self::Output {
Self(!self.0)
}
}
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[cfg_attr(feature = "2d", doc = " Collider::circle(0.5),")]
#[cfg_attr(feature = "3d", doc = " Collider::sphere(0.5),")]
#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
#[derive(Reflect, Clone, Copy, Component, Debug, PartialEq, Eq)]
#[component(immutable)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serialize", reflect(Serialize, Deserialize))]
#[reflect(Debug, Component, PartialEq)]
pub struct CollisionLayers {
#[doc(alias = "groups", alias = "layers")]
pub memberships: LayerMask,
#[doc(alias = "masks", alias = "layer_mask")]
pub filters: LayerMask,
}
impl CollisionLayers {
pub const DEFAULT: Self = Self {
memberships: LayerMask::DEFAULT,
filters: LayerMask::ALL,
};
pub const ALL: Self = Self {
memberships: LayerMask::ALL,
filters: LayerMask::ALL,
};
pub const NONE: Self = Self {
memberships: LayerMask::NONE,
filters: LayerMask::NONE,
};
pub const ALL_MEMBERSHIPS: Self = Self {
memberships: LayerMask::ALL,
filters: LayerMask::NONE,
};
pub const ALL_FILTERS: Self = Self {
memberships: LayerMask::NONE,
filters: LayerMask::ALL,
};
pub fn new(memberships: impl Into<LayerMask>, filters: impl Into<LayerMask>) -> Self {
Self {
memberships: memberships.into(),
filters: filters.into(),
}
}
pub const fn from_bits(memberships: u32, filters: u32) -> Self {
Self {
memberships: LayerMask(memberships),
filters: LayerMask(filters),
}
}
pub fn interacts_with(self, other: Self) -> bool {
(self.memberships & other.filters) != LayerMask::NONE
&& (other.memberships & self.filters) != LayerMask::NONE
}
}
impl Default for CollisionLayers {
fn default() -> Self {
CollisionLayers::DEFAULT
}
}
#[cfg(test)]
mod tests {
use crate::prelude::*;
#[derive(PhysicsLayer, Default)]
enum GameLayer {
#[default]
Default,
Player,
Enemy,
Ground,
}
#[test]
fn creation() {
let with_bitmask = CollisionLayers::new(0b00100, 0b01011);
let with_enum = CollisionLayers::new(
GameLayer::Enemy,
[GameLayer::Default, GameLayer::Player, GameLayer::Ground],
);
let with_layers =
CollisionLayers::new(LayerMask::from(GameLayer::Enemy), LayerMask(0b01011));
assert_eq!(with_bitmask, with_enum);
assert_eq!(with_bitmask, with_layers);
assert!(with_bitmask.memberships.has_all(GameLayer::Enemy));
assert!(!with_bitmask.memberships.has_all(GameLayer::Player));
assert!(
with_bitmask
.filters
.has_all([GameLayer::Player, GameLayer::Ground])
);
assert!(!with_bitmask.filters.has_all(GameLayer::Enemy));
}
}