use bitflags::bitflags;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub enum RigidBodyType {
#[default]
Dynamic,
Fixed,
KinematicPositionBased,
KinematicVelocityBased,
}
#[cfg(feature = "physics")]
impl From<RigidBodyType> for rapier3d::prelude::RigidBodyType {
fn from(value: RigidBodyType) -> Self {
match value {
RigidBodyType::Dynamic => rapier3d::prelude::RigidBodyType::Dynamic,
RigidBodyType::Fixed => rapier3d::prelude::RigidBodyType::Fixed,
RigidBodyType::KinematicPositionBased => {
rapier3d::prelude::RigidBodyType::KinematicPositionBased
}
RigidBodyType::KinematicVelocityBased => {
rapier3d::prelude::RigidBodyType::KinematicVelocityBased
}
}
}
}
#[cfg(feature = "physics")]
impl From<rapier3d::prelude::RigidBodyType> for RigidBodyType {
fn from(value: rapier3d::prelude::RigidBodyType) -> Self {
match value {
rapier3d::prelude::RigidBodyType::Dynamic => RigidBodyType::Dynamic,
rapier3d::prelude::RigidBodyType::Fixed => RigidBodyType::Fixed,
rapier3d::prelude::RigidBodyType::KinematicPositionBased => {
RigidBodyType::KinematicPositionBased
}
rapier3d::prelude::RigidBodyType::KinematicVelocityBased => {
RigidBodyType::KinematicVelocityBased
}
}
}
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default, Serialize, Deserialize)]
pub struct LockedAxes: u8 {
const TRANSLATION_LOCKED_X = 0b0000_0001;
const TRANSLATION_LOCKED_Y = 0b0000_0010;
const TRANSLATION_LOCKED_Z = 0b0000_0100;
const ROTATION_LOCKED_X = 0b0000_1000;
const ROTATION_LOCKED_Y = 0b0001_0000;
const ROTATION_LOCKED_Z = 0b0010_0000;
const TRANSLATION_LOCKED = Self::TRANSLATION_LOCKED_X.bits() | Self::TRANSLATION_LOCKED_Y.bits() | Self::TRANSLATION_LOCKED_Z.bits();
const ROTATION_LOCKED = Self::ROTATION_LOCKED_X.bits() | Self::ROTATION_LOCKED_Y.bits() | Self::ROTATION_LOCKED_Z.bits();
}
}
#[cfg(feature = "physics")]
impl From<LockedAxes> for rapier3d::prelude::LockedAxes {
fn from(value: LockedAxes) -> Self {
rapier3d::prelude::LockedAxes::from_bits_truncate(value.bits())
}
}
#[cfg(feature = "physics")]
impl From<rapier3d::prelude::LockedAxes> for LockedAxes {
fn from(value: rapier3d::prelude::LockedAxes) -> Self {
LockedAxes::from_bits_truncate(value.bits())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct InteractionGroups {
pub memberships: u32,
pub filter: u32,
}
impl Default for InteractionGroups {
fn default() -> Self {
Self::all()
}
}
impl InteractionGroups {
pub fn new(memberships: u32, filter: u32) -> Self {
Self {
memberships,
filter,
}
}
pub fn all() -> Self {
Self {
memberships: u32::MAX,
filter: u32::MAX,
}
}
pub fn none() -> Self {
Self {
memberships: 0,
filter: 0,
}
}
}
#[cfg(feature = "physics")]
impl From<InteractionGroups> for rapier3d::prelude::InteractionGroups {
fn from(value: InteractionGroups) -> Self {
rapier3d::prelude::InteractionGroups::new(
rapier3d::prelude::Group::from_bits_truncate(value.memberships),
rapier3d::prelude::Group::from_bits_truncate(value.filter),
)
}
}
#[cfg(feature = "physics")]
impl From<rapier3d::prelude::InteractionGroups> for InteractionGroups {
fn from(value: rapier3d::prelude::InteractionGroups) -> Self {
Self {
memberships: value.memberships.bits(),
filter: value.filter.bits(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct RigidBodyHandle(pub u64);
#[cfg(feature = "physics")]
impl From<rapier3d::prelude::RigidBodyHandle> for RigidBodyHandle {
fn from(value: rapier3d::prelude::RigidBodyHandle) -> Self {
let (index, generation) = value.into_raw_parts();
Self(((generation as u64) << 32) | (index as u64))
}
}
#[cfg(feature = "physics")]
impl From<RigidBodyHandle> for rapier3d::prelude::RigidBodyHandle {
fn from(value: RigidBodyHandle) -> Self {
let index = (value.0 & 0xFFFF_FFFF) as u32;
let generation = ((value.0 >> 32) & 0xFFFF_FFFF) as u32;
rapier3d::prelude::RigidBodyHandle::from_raw_parts(index, generation)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct ColliderHandle(pub u64);
#[cfg(feature = "physics")]
impl From<rapier3d::prelude::ColliderHandle> for ColliderHandle {
fn from(value: rapier3d::prelude::ColliderHandle) -> Self {
let (index, generation) = value.into_raw_parts();
Self(((generation as u64) << 32) | (index as u64))
}
}
#[cfg(feature = "physics")]
impl From<ColliderHandle> for rapier3d::prelude::ColliderHandle {
fn from(value: ColliderHandle) -> Self {
let index = (value.0 & 0xFFFF_FFFF) as u32;
let generation = ((value.0 >> 32) & 0xFFFF_FFFF) as u32;
rapier3d::prelude::ColliderHandle::from_raw_parts(index, generation)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CharacterControllerConfig {
pub offset: f32,
pub max_slope_climb_angle: f32,
pub min_slope_slide_angle: f32,
pub autostep_max_height: Option<f32>,
pub autostep_min_width: Option<f32>,
pub autostep_include_dynamic_bodies: bool,
pub snap_to_ground: Option<f32>,
}
impl Default for CharacterControllerConfig {
fn default() -> Self {
Self {
offset: 0.01,
max_slope_climb_angle: 45_f32.to_radians(),
min_slope_slide_angle: 30_f32.to_radians(),
autostep_max_height: Some(0.3),
autostep_min_width: Some(0.2),
autostep_include_dynamic_bodies: false,
snap_to_ground: Some(0.2),
}
}
}
#[cfg(feature = "physics")]
impl CharacterControllerConfig {
pub fn to_rapier(&self, scale: f32) -> rapier3d::control::KinematicCharacterController {
rapier3d::control::KinematicCharacterController {
offset: rapier3d::control::CharacterLength::Absolute(self.offset * scale),
up: nalgebra::Vector3::y_axis(),
max_slope_climb_angle: self.max_slope_climb_angle,
min_slope_slide_angle: self.min_slope_slide_angle,
autostep: self.autostep_max_height.map(|max_height| {
rapier3d::control::CharacterAutostep {
max_height: rapier3d::control::CharacterLength::Absolute(max_height * scale),
min_width: rapier3d::control::CharacterLength::Absolute(
self.autostep_min_width.unwrap_or(0.2) * scale,
),
include_dynamic_bodies: self.autostep_include_dynamic_bodies,
}
}),
snap_to_ground: self
.snap_to_ground
.map(|d| rapier3d::control::CharacterLength::Absolute(d * scale)),
..Default::default()
}
}
}