1use crate::scene::node::constructor::NodeConstructor;
32use crate::{
33 core::{
34 algebra::{Matrix4, Vector3},
35 log::Log,
36 math::{aabb::AxisAlignedBoundingBox, m4x4_approx_eq},
37 parking_lot::Mutex,
38 pool::Handle,
39 reflect::prelude::*,
40 type_traits::prelude::*,
41 uuid::{uuid, Uuid},
42 variable::InheritableVariable,
43 visitor::prelude::*,
44 },
45 scene::{
46 base::{Base, BaseBuilder},
47 collider::Collider,
48 graph::Graph,
49 node::{Node, NodeTrait, SyncContext, UpdateContext},
50 Scene,
51 },
52};
53use fyrox_core::uuid_provider;
54use fyrox_graph::constructor::ConstructorProvider;
55use fyrox_graph::{BaseSceneGraph, SceneGraph};
56use rapier3d::{dynamics, prelude::RigidBodyHandle};
57use std::{
58 cell::Cell,
59 collections::VecDeque,
60 fmt::{Debug, Formatter},
61 ops::{Deref, DerefMut},
62};
63use strum_macros::{AsRefStr, EnumString, VariantNames};
64
65#[derive(
67 Copy, Clone, Debug, Reflect, Visit, PartialEq, Eq, Hash, AsRefStr, EnumString, VariantNames,
68)]
69#[repr(u32)]
70pub enum RigidBodyType {
71 Dynamic = 0,
73 Static = 1,
75 KinematicPositionBased = 2,
78 KinematicVelocityBased = 3,
81}
82
83uuid_provider!(RigidBodyType = "562d2907-1b41-483a-8ca2-12eebaff7f5d");
84
85impl Default for RigidBodyType {
86 fn default() -> Self {
87 Self::Dynamic
88 }
89}
90
91impl From<dynamics::RigidBodyType> for RigidBodyType {
92 fn from(s: dynamics::RigidBodyType) -> Self {
93 match s {
94 dynamics::RigidBodyType::Dynamic => Self::Dynamic,
95 dynamics::RigidBodyType::Fixed => Self::Static,
96 dynamics::RigidBodyType::KinematicPositionBased => Self::KinematicPositionBased,
97 dynamics::RigidBodyType::KinematicVelocityBased => Self::KinematicVelocityBased,
98 }
99 }
100}
101
102impl From<RigidBodyType> for rapier3d::dynamics::RigidBodyType {
103 fn from(v: RigidBodyType) -> Self {
104 match v {
105 RigidBodyType::Dynamic => rapier3d::dynamics::RigidBodyType::Dynamic,
106 RigidBodyType::Static => rapier3d::dynamics::RigidBodyType::Fixed,
107 RigidBodyType::KinematicPositionBased => {
108 rapier3d::dynamics::RigidBodyType::KinematicPositionBased
109 }
110 RigidBodyType::KinematicVelocityBased => {
111 rapier3d::dynamics::RigidBodyType::KinematicVelocityBased
112 }
113 }
114 }
115}
116
117impl From<RigidBodyType> for rapier2d::dynamics::RigidBodyType {
118 fn from(v: RigidBodyType) -> Self {
119 match v {
120 RigidBodyType::Dynamic => rapier2d::dynamics::RigidBodyType::Dynamic,
121 RigidBodyType::Static => rapier2d::dynamics::RigidBodyType::Fixed,
122 RigidBodyType::KinematicPositionBased => {
123 rapier2d::dynamics::RigidBodyType::KinematicPositionBased
124 }
125 RigidBodyType::KinematicVelocityBased => {
126 rapier2d::dynamics::RigidBodyType::KinematicVelocityBased
127 }
128 }
129 }
130}
131
132#[derive(Debug)]
133pub(crate) enum ApplyAction {
134 Force(Vector3<f32>),
135 Torque(Vector3<f32>),
136 ForceAtPoint {
137 force: Vector3<f32>,
138 point: Vector3<f32>,
139 },
140 Impulse(Vector3<f32>),
141 TorqueImpulse(Vector3<f32>),
142 ImpulseAtPoint {
143 impulse: Vector3<f32>,
144 point: Vector3<f32>,
145 },
146 WakeUp,
147}
148
149#[derive(Visit, Reflect, ComponentProvider)]
157pub struct RigidBody {
158 base: Base,
159
160 #[reflect(setter = "set_lin_vel")]
161 pub(crate) lin_vel: InheritableVariable<Vector3<f32>>,
162
163 #[reflect(setter = "set_ang_vel")]
164 pub(crate) ang_vel: InheritableVariable<Vector3<f32>>,
165
166 #[reflect(setter = "set_lin_damping")]
167 pub(crate) lin_damping: InheritableVariable<f32>,
168
169 #[reflect(setter = "set_ang_damping")]
170 pub(crate) ang_damping: InheritableVariable<f32>,
171
172 #[reflect(setter = "set_body_type")]
173 pub(crate) body_type: InheritableVariable<RigidBodyType>,
174
175 #[reflect(min_value = 0.0, step = 0.05)]
176 #[reflect(setter = "set_mass")]
177 pub(crate) mass: InheritableVariable<f32>,
178
179 #[reflect(setter = "lock_x_rotations")]
180 pub(crate) x_rotation_locked: InheritableVariable<bool>,
181
182 #[reflect(setter = "lock_y_rotations")]
183 pub(crate) y_rotation_locked: InheritableVariable<bool>,
184
185 #[reflect(setter = "lock_z_rotations")]
186 pub(crate) z_rotation_locked: InheritableVariable<bool>,
187
188 #[reflect(setter = "lock_translation")]
189 pub(crate) translation_locked: InheritableVariable<bool>,
190
191 #[reflect(setter = "enable_ccd")]
192 pub(crate) ccd_enabled: InheritableVariable<bool>,
193
194 #[reflect(setter = "set_can_sleep")]
195 pub(crate) can_sleep: InheritableVariable<bool>,
196
197 #[reflect(setter = "set_dominance")]
198 pub(crate) dominance: InheritableVariable<i8>,
199
200 #[reflect(setter = "set_gravity_scale")]
201 pub(crate) gravity_scale: InheritableVariable<f32>,
202
203 #[visit(skip)]
204 #[reflect(hidden)]
205 pub(crate) sleeping: bool,
206 #[visit(skip)]
207 #[reflect(hidden)]
208 pub(crate) reset_forces: Cell<bool>,
209 #[visit(skip)]
210 #[reflect(hidden)]
211 pub(crate) native: Cell<RigidBodyHandle>,
212 #[visit(skip)]
213 #[reflect(hidden)]
214 pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
215}
216
217impl Debug for RigidBody {
218 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
219 write!(f, "RigidBody")
220 }
221}
222
223impl Default for RigidBody {
224 fn default() -> Self {
225 Self {
226 base: Default::default(),
227 lin_vel: Default::default(),
228 ang_vel: Default::default(),
229 lin_damping: Default::default(),
230 ang_damping: Default::default(),
231 sleeping: Default::default(),
232 body_type: InheritableVariable::new_modified(RigidBodyType::Dynamic),
233 mass: InheritableVariable::new_modified(1.0),
234 x_rotation_locked: Default::default(),
235 y_rotation_locked: Default::default(),
236 z_rotation_locked: Default::default(),
237 translation_locked: Default::default(),
238 ccd_enabled: Default::default(),
239 can_sleep: InheritableVariable::new_modified(true),
240 dominance: Default::default(),
241 gravity_scale: InheritableVariable::new_modified(1.0),
242 native: Cell::new(RigidBodyHandle::invalid()),
243 actions: Default::default(),
244 reset_forces: Default::default(),
245 }
246 }
247}
248
249impl Deref for RigidBody {
250 type Target = Base;
251
252 fn deref(&self) -> &Self::Target {
253 &self.base
254 }
255}
256
257impl DerefMut for RigidBody {
258 fn deref_mut(&mut self) -> &mut Self::Target {
259 &mut self.base
260 }
261}
262
263impl Clone for RigidBody {
264 fn clone(&self) -> Self {
265 Self {
266 base: self.base.clone(),
267 lin_vel: self.lin_vel.clone(),
268 ang_vel: self.ang_vel.clone(),
269 lin_damping: self.lin_damping.clone(),
270 ang_damping: self.ang_damping.clone(),
271 sleeping: self.sleeping,
272 body_type: self.body_type.clone(),
273 mass: self.mass.clone(),
274 x_rotation_locked: self.x_rotation_locked.clone(),
275 y_rotation_locked: self.y_rotation_locked.clone(),
276 z_rotation_locked: self.z_rotation_locked.clone(),
277 translation_locked: self.translation_locked.clone(),
278 ccd_enabled: self.ccd_enabled.clone(),
279 can_sleep: self.can_sleep.clone(),
280 dominance: self.dominance.clone(),
281 gravity_scale: self.gravity_scale.clone(),
282 native: Cell::new(RigidBodyHandle::invalid()),
284 actions: Default::default(),
285 reset_forces: self.reset_forces.clone(),
286 }
287 }
288}
289
290impl TypeUuidProvider for RigidBody {
291 fn type_uuid() -> Uuid {
292 uuid!("4be15a7c-3566-49c4-bba8-2f4ccc57ffed")
293 }
294}
295
296impl RigidBody {
297 pub fn set_lin_vel(&mut self, lin_vel: Vector3<f32>) -> Vector3<f32> {
300 self.lin_vel.set_value_and_mark_modified(lin_vel)
301 }
302
303 pub fn lin_vel(&self) -> Vector3<f32> {
305 *self.lin_vel
306 }
307
308 pub fn set_ang_vel(&mut self, ang_vel: Vector3<f32>) -> Vector3<f32> {
311 self.ang_vel.set_value_and_mark_modified(ang_vel)
312 }
313
314 pub fn ang_vel(&self) -> Vector3<f32> {
316 *self.ang_vel
317 }
318
319 pub fn set_mass(&mut self, mass: f32) -> f32 {
322 self.mass.set_value_and_mark_modified(mass)
323 }
324
325 pub fn mass(&self) -> f32 {
327 *self.mass
328 }
329
330 pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
333 self.ang_damping.set_value_and_mark_modified(damping)
334 }
335
336 pub fn ang_damping(&self) -> f32 {
338 *self.ang_damping
339 }
340
341 pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
344 self.lin_damping.set_value_and_mark_modified(damping)
345 }
346
347 pub fn lin_damping(&self) -> f32 {
349 *self.lin_damping
350 }
351
352 pub fn lock_x_rotations(&mut self, state: bool) -> bool {
354 self.x_rotation_locked.set_value_and_mark_modified(state)
355 }
356
357 pub fn is_x_rotation_locked(&self) -> bool {
359 *self.x_rotation_locked
360 }
361
362 pub fn lock_y_rotations(&mut self, state: bool) -> bool {
364 self.y_rotation_locked.set_value_and_mark_modified(state)
365 }
366
367 pub fn is_y_rotation_locked(&self) -> bool {
369 *self.y_rotation_locked
370 }
371
372 pub fn lock_z_rotations(&mut self, state: bool) -> bool {
374 self.z_rotation_locked.set_value_and_mark_modified(state)
375 }
376
377 pub fn is_z_rotation_locked(&self) -> bool {
379 *self.z_rotation_locked
380 }
381
382 pub fn lock_rotations(&mut self, locked: bool) {
384 self.x_rotation_locked.set_value_and_mark_modified(locked);
385 self.y_rotation_locked.set_value_and_mark_modified(locked);
386 self.z_rotation_locked.set_value_and_mark_modified(locked);
387 }
388
389 pub fn lock_translation(&mut self, state: bool) -> bool {
391 self.translation_locked.set_value_and_mark_modified(state)
392 }
393
394 pub fn is_translation_locked(&self) -> bool {
396 *self.translation_locked
397 }
398
399 pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
401 self.body_type.set_value_and_mark_modified(body_type)
402 }
403
404 pub fn body_type(&self) -> RigidBodyType {
406 *self.body_type
407 }
408
409 pub fn is_sleeping(&self) -> bool {
412 self.sleeping
413 }
414
415 pub fn is_ccd_enabled(&self) -> bool {
417 *self.ccd_enabled
418 }
419
420 pub fn enable_ccd(&mut self, enable: bool) -> bool {
423 self.ccd_enabled.set_value_and_mark_modified(enable)
424 }
425
426 pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
428 self.gravity_scale.set_value_and_mark_modified(scale)
429 }
430
431 pub fn gravity_scale(&self) -> f32 {
433 *self.gravity_scale
434 }
435
436 pub fn set_dominance(&mut self, dominance: i8) -> i8 {
441 self.dominance.set_value_and_mark_modified(dominance)
442 }
443
444 pub fn dominance(&self) -> i8 {
446 *self.dominance
447 }
448
449 pub fn apply_force(&mut self, force: Vector3<f32>) {
452 self.actions.get_mut().push_back(ApplyAction::Force(force))
453 }
454
455 pub fn apply_torque(&mut self, torque: Vector3<f32>) {
458 self.actions
459 .get_mut()
460 .push_back(ApplyAction::Torque(torque))
461 }
462
463 pub fn apply_force_at_point(&mut self, force: Vector3<f32>, point: Vector3<f32>) {
466 self.actions
467 .get_mut()
468 .push_back(ApplyAction::ForceAtPoint { force, point })
469 }
470
471 pub fn apply_impulse(&mut self, impulse: Vector3<f32>) {
474 self.actions
475 .get_mut()
476 .push_back(ApplyAction::Impulse(impulse))
477 }
478
479 pub fn apply_torque_impulse(&mut self, torque_impulse: Vector3<f32>) {
482 self.actions
483 .get_mut()
484 .push_back(ApplyAction::TorqueImpulse(torque_impulse))
485 }
486
487 pub fn apply_impulse_at_point(&mut self, impulse: Vector3<f32>, point: Vector3<f32>) {
491 self.actions
492 .get_mut()
493 .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
494 }
495
496 pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
499 self.can_sleep.set_value_and_mark_modified(can_sleep)
500 }
501
502 pub fn is_can_sleep(&self) -> bool {
504 *self.can_sleep
505 }
506
507 pub fn wake_up(&mut self) {
509 self.actions.get_mut().push_back(ApplyAction::WakeUp)
510 }
511
512 pub(crate) fn need_sync_model(&self) -> bool {
513 self.lin_vel.need_sync()
514 || self.ang_vel.need_sync()
515 || self.lin_damping.need_sync()
516 || self.ang_damping.need_sync()
517 || self.body_type.need_sync()
518 || self.mass.need_sync()
519 || self.x_rotation_locked.need_sync()
520 || self.y_rotation_locked.need_sync()
521 || self.z_rotation_locked.need_sync()
522 || self.translation_locked.need_sync()
523 || self.ccd_enabled.need_sync()
524 || self.can_sleep.need_sync()
525 || self.dominance.need_sync()
526 || self.gravity_scale.need_sync()
527 || self.reset_forces.get()
528 }
529}
530
531impl ConstructorProvider<Node, Graph> for RigidBody {
532 fn constructor() -> NodeConstructor {
533 NodeConstructor::new::<Self>()
534 .with_variant("Rigid Body", |_| {
535 RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body"))
536 .build_node()
537 .into()
538 })
539 .with_group("Physics")
540 }
541}
542
543impl NodeTrait for RigidBody {
544 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
545 self.base.local_bounding_box()
546 }
547
548 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
549 self.base.world_bounding_box()
550 }
551
552 fn id(&self) -> Uuid {
553 Self::type_uuid()
554 }
555
556 fn on_removed_from_graph(&mut self, graph: &mut Graph) {
557 graph.physics.remove_body(self.native.get());
558 self.native.set(RigidBodyHandle::invalid());
559
560 Log::info(format!(
561 "Native rigid body was removed for node: {}",
562 self.name()
563 ));
564 }
565
566 fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
567 context.physics.sync_to_rigid_body_node(self_handle, self);
568 }
569
570 fn on_global_transform_changed(
571 &self,
572 new_global_transform: &Matrix4<f32>,
573 context: &mut SyncContext,
574 ) {
575 if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
576 context
577 .physics
578 .set_rigid_body_position(self, new_global_transform);
579 }
580 }
581
582 fn update(&mut self, context: &mut UpdateContext) {
583 context.physics.sync_rigid_body_node(
584 self,
585 context
587 .nodes
588 .try_borrow(self.parent)
589 .map(|p| p.global_transform())
590 .unwrap_or_else(Matrix4::identity),
591 );
592 }
593
594 fn validate(&self, scene: &Scene) -> Result<(), String> {
595 for &child in self.children() {
596 if scene.graph.try_get_of_type::<Collider>(child).is_some() {
597 return Ok(());
598 }
599 }
600
601 Err("The 3D rigid body must have at least one 3D collider as a \
602 direct child node to work correctly!"
603 .to_string())
604 }
605}
606
607pub struct RigidBodyBuilder {
609 base_builder: BaseBuilder,
610 lin_vel: Vector3<f32>,
611 ang_vel: Vector3<f32>,
612 lin_damping: f32,
613 ang_damping: f32,
614 sleeping: bool,
615 body_type: RigidBodyType,
616 mass: f32,
617 x_rotation_locked: bool,
618 y_rotation_locked: bool,
619 z_rotation_locked: bool,
620 translation_locked: bool,
621 ccd_enabled: bool,
622 can_sleep: bool,
623 dominance: i8,
624 gravity_scale: f32,
625}
626
627impl RigidBodyBuilder {
628 pub fn new(base_builder: BaseBuilder) -> Self {
630 Self {
631 base_builder,
632 lin_vel: Default::default(),
633 ang_vel: Default::default(),
634 lin_damping: 0.0,
635 ang_damping: 0.0,
636 sleeping: false,
637 body_type: RigidBodyType::Dynamic,
638 mass: 1.0,
639 x_rotation_locked: false,
640 y_rotation_locked: false,
641 z_rotation_locked: false,
642 translation_locked: false,
643 ccd_enabled: false,
644 can_sleep: true,
645 dominance: 0,
646 gravity_scale: 1.0,
647 }
648 }
649
650 pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
652 self.body_type = body_type;
653 self
654 }
655
656 pub fn with_mass(mut self, mass: f32) -> Self {
658 self.mass = mass;
659 self
660 }
661
662 pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
664 self.ccd_enabled = enabled;
665 self
666 }
667
668 pub fn with_lin_vel(mut self, lin_vel: Vector3<f32>) -> Self {
670 self.lin_vel = lin_vel;
671 self
672 }
673
674 pub fn with_ang_vel(mut self, ang_vel: Vector3<f32>) -> Self {
676 self.ang_vel = ang_vel;
677 self
678 }
679
680 pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
682 self.ang_damping = ang_damping;
683 self
684 }
685
686 pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
688 self.lin_damping = lin_damping;
689 self
690 }
691
692 pub fn with_x_rotation_locked(mut self, x_rotation_locked: bool) -> Self {
694 self.x_rotation_locked = x_rotation_locked;
695 self
696 }
697
698 pub fn with_y_rotation_locked(mut self, y_rotation_locked: bool) -> Self {
700 self.y_rotation_locked = y_rotation_locked;
701 self
702 }
703
704 pub fn with_z_rotation_locked(mut self, z_rotation_locked: bool) -> Self {
706 self.z_rotation_locked = z_rotation_locked;
707 self
708 }
709
710 pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
712 self.translation_locked = translation_locked;
713 self
714 }
715
716 pub fn with_locked_rotations(mut self, locked: bool) -> Self {
718 self.x_rotation_locked = locked;
719 self.y_rotation_locked = locked;
720 self.z_rotation_locked = locked;
721 self
722 }
723
724 pub fn with_sleeping(mut self, sleeping: bool) -> Self {
726 self.sleeping = sleeping;
727 self
728 }
729
730 pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
732 self.can_sleep = can_sleep;
733 self
734 }
735
736 pub fn with_dominance(mut self, dominance: i8) -> Self {
738 self.dominance = dominance;
739 self
740 }
741
742 pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
744 self.gravity_scale = gravity_scale;
745 self
746 }
747
748 pub fn build_rigid_body(self) -> RigidBody {
750 RigidBody {
751 base: self.base_builder.build_base(),
752 lin_vel: self.lin_vel.into(),
753 ang_vel: self.ang_vel.into(),
754 lin_damping: self.lin_damping.into(),
755 ang_damping: self.ang_damping.into(),
756 sleeping: self.sleeping,
757 body_type: self.body_type.into(),
758 mass: self.mass.into(),
759 x_rotation_locked: self.x_rotation_locked.into(),
760 y_rotation_locked: self.y_rotation_locked.into(),
761 z_rotation_locked: self.z_rotation_locked.into(),
762 translation_locked: self.translation_locked.into(),
763 ccd_enabled: self.ccd_enabled.into(),
764 can_sleep: self.can_sleep.into(),
765 dominance: self.dominance.into(),
766 gravity_scale: self.gravity_scale.into(),
767 native: Cell::new(RigidBodyHandle::invalid()),
768 actions: Default::default(),
769 reset_forces: Default::default(),
770 }
771 }
772
773 pub fn build_node(self) -> Node {
775 Node::new(self.build_rigid_body())
776 }
777
778 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
780 graph.add_node(self.build_node())
781 }
782}