use crate::{
core::{
algebra::Vector2,
inspect::{Inspect, PropertyInfo},
parking_lot::Mutex,
pool::Handle,
visitor::prelude::*,
},
scene::{
base::{Base, BaseBuilder},
graph::Graph,
node::Node,
rigidbody::{RigidBodyChanges, RigidBodyType},
},
};
use rapier2d::prelude::RigidBodyHandle;
use std::{
cell::Cell,
collections::VecDeque,
fmt::{Debug, Formatter},
ops::{Deref, DerefMut},
};
#[derive(Debug)]
pub(crate) enum ApplyAction {
Force(Vector2<f32>),
Torque(f32),
ForceAtPoint {
force: Vector2<f32>,
point: Vector2<f32>,
},
Impulse(Vector2<f32>),
TorqueImpulse(f32),
ImpulseAtPoint {
impulse: Vector2<f32>,
point: Vector2<f32>,
},
WakeUp,
}
#[derive(Visit, Inspect)]
pub struct RigidBody {
base: Base,
pub(crate) lin_vel: Vector2<f32>,
pub(crate) ang_vel: f32,
pub(crate) lin_damping: f32,
pub(crate) ang_damping: f32,
#[visit(skip)]
#[inspect(skip)]
pub(crate) sleeping: bool,
body_type: RigidBodyType,
#[inspect(min_value = 0.0, step = 0.05)]
mass: f32,
rotation_locked: bool,
translation_locked: bool,
ccd_enabled: bool,
can_sleep: bool,
#[visit(skip)]
#[inspect(skip)]
pub(crate) native: Cell<RigidBodyHandle>,
#[visit(skip)]
#[inspect(skip)]
pub(crate) changes: Cell<RigidBodyChanges>,
#[visit(skip)]
#[inspect(skip)]
pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
}
impl Debug for RigidBody {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "RigidBody")
}
}
impl Default for RigidBody {
fn default() -> Self {
Self {
base: Default::default(),
lin_vel: Default::default(),
ang_vel: Default::default(),
lin_damping: 0.0,
ang_damping: 0.0,
sleeping: false,
body_type: RigidBodyType::Dynamic,
mass: 1.0,
rotation_locked: false,
translation_locked: false,
ccd_enabled: false,
can_sleep: true,
native: Cell::new(RigidBodyHandle::invalid()),
changes: Cell::new(RigidBodyChanges::NONE),
actions: Default::default(),
}
}
}
impl Deref for RigidBody {
type Target = Base;
fn deref(&self) -> &Self::Target {
&self.base
}
}
impl DerefMut for RigidBody {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.base
}
}
impl RigidBody {
pub fn raw_copy(&self) -> Self {
Self {
base: self.base.raw_copy(),
lin_vel: self.lin_vel,
ang_vel: self.ang_vel,
lin_damping: self.lin_damping,
ang_damping: self.ang_damping,
sleeping: self.sleeping,
body_type: self.body_type,
mass: self.mass,
rotation_locked: self.rotation_locked,
translation_locked: self.translation_locked,
ccd_enabled: self.ccd_enabled,
can_sleep: self.can_sleep,
native: Cell::new(RigidBodyHandle::invalid()),
changes: Cell::new(RigidBodyChanges::NONE),
actions: Default::default(),
}
}
pub fn set_lin_vel(&mut self, lin_vel: Vector2<f32>) {
self.lin_vel = lin_vel;
self.changes.get_mut().insert(RigidBodyChanges::LIN_VEL);
}
pub fn lin_vel(&self) -> Vector2<f32> {
self.lin_vel
}
pub fn set_ang_vel(&mut self, ang_vel: f32) {
self.ang_vel = ang_vel;
self.changes.get_mut().insert(RigidBodyChanges::ANG_VEL);
}
pub fn ang_vel(&self) -> f32 {
self.ang_vel
}
pub fn set_mass(&mut self, mass: f32) {
self.mass = mass;
self.changes.get_mut().insert(RigidBodyChanges::MASS);
}
pub fn mass(&self) -> f32 {
self.mass
}
pub fn set_ang_damping(&mut self, damping: f32) {
self.ang_damping = damping;
self.changes.get_mut().insert(RigidBodyChanges::ANG_DAMPING);
}
pub fn ang_damping(&self) -> f32 {
self.ang_damping
}
pub fn set_lin_damping(&mut self, damping: f32) {
self.lin_damping = damping;
self.changes.get_mut().insert(RigidBodyChanges::LIN_DAMPING);
}
pub fn lin_damping(&self) -> f32 {
self.lin_damping
}
pub fn lock_rotations(&mut self, state: bool) {
self.rotation_locked = state;
self.changes
.get_mut()
.insert(RigidBodyChanges::ROTATION_LOCKED);
}
pub fn is_rotation_locked(&self) -> bool {
self.rotation_locked
}
pub fn lock_translation(&mut self, state: bool) {
self.translation_locked = state;
self.changes
.get_mut()
.insert(RigidBodyChanges::TRANSLATION_LOCKED);
}
pub fn is_translation_locked(&self) -> bool {
self.translation_locked
}
pub fn set_body_type(&mut self, body_type: RigidBodyType) {
self.body_type = body_type;
self.changes.get_mut().insert(RigidBodyChanges::BODY_TYPE);
}
pub fn body_type(&self) -> RigidBodyType {
self.body_type
}
pub fn is_sleeping(&self) -> bool {
self.sleeping
}
pub fn is_ccd_enabled(&self) -> bool {
self.ccd_enabled
}
pub fn enable_ccd(&mut self, enable: bool) {
self.ccd_enabled = enable;
self.changes.get_mut().insert(RigidBodyChanges::CCD_STATE);
}
pub fn apply_force(&mut self, force: Vector2<f32>) {
self.actions.get_mut().push_back(ApplyAction::Force(force))
}
pub fn apply_torque(&mut self, torque: f32) {
self.actions
.get_mut()
.push_back(ApplyAction::Torque(torque))
}
pub fn apply_force_at_point(&mut self, force: Vector2<f32>, point: Vector2<f32>) {
self.actions
.get_mut()
.push_back(ApplyAction::ForceAtPoint { force, point })
}
pub fn apply_impulse(&mut self, impulse: Vector2<f32>) {
self.actions
.get_mut()
.push_back(ApplyAction::Impulse(impulse))
}
pub fn apply_torque_impulse(&mut self, torque_impulse: f32) {
self.actions
.get_mut()
.push_back(ApplyAction::TorqueImpulse(torque_impulse))
}
pub fn apply_impulse_at_point(&mut self, impulse: Vector2<f32>, point: Vector2<f32>) {
self.actions
.get_mut()
.push_back(ApplyAction::ImpulseAtPoint { impulse, point })
}
pub fn set_can_sleep(&mut self, can_sleep: bool) {
self.can_sleep = can_sleep;
self.changes.get_mut().insert(RigidBodyChanges::CAN_SLEEP);
}
pub fn is_can_sleep(&self) -> bool {
self.can_sleep
}
pub fn wake_up(&mut self) {
self.actions.get_mut().push_back(ApplyAction::WakeUp)
}
}
pub struct RigidBodyBuilder {
base_builder: BaseBuilder,
lin_vel: Vector2<f32>,
ang_vel: f32,
lin_damping: f32,
ang_damping: f32,
sleeping: bool,
body_type: RigidBodyType,
mass: f32,
rotation_locked: bool,
translation_locked: bool,
ccd_enabled: bool,
can_sleep: bool,
}
impl RigidBodyBuilder {
pub fn new(base_builder: BaseBuilder) -> Self {
Self {
base_builder,
lin_vel: Default::default(),
ang_vel: Default::default(),
lin_damping: 0.0,
ang_damping: 0.0,
sleeping: false,
body_type: RigidBodyType::Dynamic,
mass: 1.0,
rotation_locked: false,
translation_locked: false,
ccd_enabled: false,
can_sleep: true,
}
}
pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
self.body_type = body_type;
self
}
pub fn with_mass(mut self, mass: f32) -> Self {
self.mass = mass;
self
}
pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
self.ccd_enabled = enabled;
self
}
pub fn with_lin_vel(mut self, lin_vel: Vector2<f32>) -> Self {
self.lin_vel = lin_vel;
self
}
pub fn with_ang_vel(mut self, ang_vel: f32) -> Self {
self.ang_vel = ang_vel;
self
}
pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
self.ang_damping = ang_damping;
self
}
pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
self.lin_damping = lin_damping;
self
}
pub fn with_rotation_locked(mut self, rotation_locked: bool) -> Self {
self.rotation_locked = rotation_locked;
self
}
pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
self.translation_locked = translation_locked;
self
}
pub fn with_sleeping(mut self, sleeping: bool) -> Self {
self.sleeping = sleeping;
self
}
pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
self.can_sleep = can_sleep;
self
}
pub fn build_node(self) -> Node {
let rigid_body = RigidBody {
base: self.base_builder.build_base(),
lin_vel: self.lin_vel,
ang_vel: self.ang_vel,
lin_damping: self.lin_damping,
ang_damping: self.ang_damping,
sleeping: self.sleeping,
body_type: self.body_type,
mass: self.mass,
rotation_locked: self.rotation_locked,
translation_locked: self.translation_locked,
ccd_enabled: self.ccd_enabled,
can_sleep: self.can_sleep,
native: Cell::new(RigidBodyHandle::invalid()),
changes: Cell::new(RigidBodyChanges::NONE),
actions: Default::default(),
};
Node::RigidBody2D(rigid_body)
}
pub fn build(self, graph: &mut Graph) -> Handle<Node> {
graph.add_node(self.build_node())
}
}