use crate::geometry::{Collider, CollisionGroups, ShapeCastHit};
use crate::math::{Real, Rot, Vect};
use bevy::prelude::*;
use crate::plugin::context::RapierContextColliders;
pub use rapier::control::CharacterAutostep;
pub use rapier::control::CharacterLength;
use rapier::prelude::{ColliderSet, QueryFilterFlags};
#[derive(Copy, Clone, PartialEq, Debug)]
pub struct CharacterCollision {
pub entity: Entity,
pub character_translation: Vect,
pub character_rotation: Rot,
pub translation_applied: Vect,
pub translation_remaining: Vect,
pub hit: ShapeCastHit,
}
impl CharacterCollision {
pub(crate) fn from_raw(
ctxt: &RapierContextColliders,
c: &rapier::control::CharacterCollision,
) -> Option<Self> {
Self::from_raw_with_set(&ctxt.colliders, c, true)
}
pub(crate) fn from_raw_with_set(
colliders: &ColliderSet,
c: &rapier::control::CharacterCollision,
details_always_computed: bool,
) -> Option<Self> {
RapierContextColliders::collider_entity_with_set(colliders, c.handle).map(|entity| {
CharacterCollision {
entity,
character_translation: c.character_pos.translation.vector.into(),
#[cfg(feature = "dim2")]
character_rotation: c.character_pos.rotation.angle(),
#[cfg(feature = "dim3")]
character_rotation: c.character_pos.rotation.into(),
translation_applied: c.translation_applied.into(),
translation_remaining: c.translation_remaining.into(),
hit: ShapeCastHit::from_rapier(c.hit, details_always_computed),
}
})
}
}
#[derive(Clone, Debug, Copy, PartialEq)]
pub struct MoveShapeOptions {
pub up: Vect,
pub offset: CharacterLength,
pub slide: bool,
pub autostep: Option<CharacterAutostep>,
pub max_slope_climb_angle: Real,
pub min_slope_slide_angle: Real,
pub apply_impulse_to_dynamic_bodies: bool,
pub snap_to_ground: Option<CharacterLength>,
pub normal_nudge_factor: Real,
}
impl Default for MoveShapeOptions {
fn default() -> Self {
let def = rapier::control::KinematicCharacterController::default();
Self {
up: def.up.into(),
offset: def.offset,
slide: def.slide,
autostep: def.autostep,
max_slope_climb_angle: def.max_slope_climb_angle,
min_slope_slide_angle: def.min_slope_slide_angle,
apply_impulse_to_dynamic_bodies: true,
snap_to_ground: def.snap_to_ground,
normal_nudge_factor: def.normal_nudge_factor,
}
}
}
#[derive(Clone, Debug, Component)] pub struct KinematicCharacterController {
pub translation: Option<Vect>,
pub custom_shape: Option<(Collider, Vect, Rot)>,
pub custom_mass: Option<Real>,
pub up: Vect,
pub offset: CharacterLength,
pub slide: bool,
pub autostep: Option<CharacterAutostep>,
pub max_slope_climb_angle: Real,
pub min_slope_slide_angle: Real,
pub apply_impulse_to_dynamic_bodies: bool,
pub snap_to_ground: Option<CharacterLength>,
pub filter_flags: QueryFilterFlags,
pub filter_groups: Option<CollisionGroups>,
pub normal_nudge_factor: Real,
}
impl KinematicCharacterController {
pub(crate) fn to_raw(&self) -> Option<rapier::control::KinematicCharacterController> {
let autostep = self.autostep.map(|autostep| CharacterAutostep {
max_height: autostep.max_height,
min_width: autostep.min_width,
include_dynamic_bodies: autostep.include_dynamic_bodies,
});
Some(rapier::control::KinematicCharacterController {
up: self.up.try_into().ok()?,
offset: self.offset,
slide: self.slide,
autostep,
max_slope_climb_angle: self.max_slope_climb_angle,
min_slope_slide_angle: self.min_slope_slide_angle,
snap_to_ground: self.snap_to_ground,
normal_nudge_factor: self.normal_nudge_factor,
})
}
}
impl Default for KinematicCharacterController {
fn default() -> Self {
let def = rapier::control::KinematicCharacterController::default();
Self {
translation: None,
custom_shape: None,
custom_mass: None,
up: def.up.into(),
offset: def.offset,
slide: def.slide,
autostep: def.autostep,
max_slope_climb_angle: def.max_slope_climb_angle,
min_slope_slide_angle: def.min_slope_slide_angle,
apply_impulse_to_dynamic_bodies: true,
snap_to_ground: def.snap_to_ground,
filter_flags: QueryFilterFlags::default() | QueryFilterFlags::EXCLUDE_SENSORS,
filter_groups: None,
normal_nudge_factor: def.normal_nudge_factor,
}
}
}
#[derive(Clone, PartialEq, Debug, Default, Component)]
pub struct KinematicCharacterControllerOutput {
pub grounded: bool,
pub desired_translation: Vect,
pub effective_translation: Vect,
pub collisions: Vec<CharacterCollision>,
pub is_sliding_down_slope: bool,
}
pub struct MoveShapeOutput {
pub grounded: bool,
pub effective_translation: Vect,
pub is_sliding_down_slope: bool,
}