1use crate::scene::node::constructor::NodeConstructor;
32use crate::{
33 core::{
34 algebra::{Matrix4, Vector2},
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 dim2::collider::Collider,
48 graph::Graph,
49 node::{Node, NodeTrait, SyncContext, UpdateContext},
50 rigidbody::RigidBodyType,
51 Scene,
52 },
53};
54use fyrox_graph::constructor::ConstructorProvider;
55use fyrox_graph::{BaseSceneGraph, SceneGraph};
56use rapier2d::prelude::RigidBodyHandle;
57use std::{
58 cell::Cell,
59 collections::VecDeque,
60 fmt::{Debug, Formatter},
61 ops::{Deref, DerefMut},
62};
63
64#[derive(Debug)]
65pub(crate) enum ApplyAction {
66 Force(Vector2<f32>),
67 Torque(f32),
68 ForceAtPoint {
69 force: Vector2<f32>,
70 point: Vector2<f32>,
71 },
72 Impulse(Vector2<f32>),
73 TorqueImpulse(f32),
74 ImpulseAtPoint {
75 impulse: Vector2<f32>,
76 point: Vector2<f32>,
77 },
78 WakeUp,
79}
80
81#[derive(Visit, Reflect, ComponentProvider)]
89pub struct RigidBody {
90 base: Base,
91
92 #[reflect(setter = "set_lin_vel")]
93 pub(crate) lin_vel: InheritableVariable<Vector2<f32>>,
94
95 #[reflect(setter = "set_ang_vel")]
96 pub(crate) ang_vel: InheritableVariable<f32>,
97
98 #[reflect(setter = "set_lin_damping")]
99 pub(crate) lin_damping: InheritableVariable<f32>,
100
101 #[reflect(setter = "set_ang_damping")]
102 pub(crate) ang_damping: InheritableVariable<f32>,
103
104 #[reflect(setter = "set_body_type")]
105 pub(crate) body_type: InheritableVariable<RigidBodyType>,
106
107 #[reflect(min_value = 0.0, step = 0.05)]
108 #[reflect(setter = "set_mass")]
109 pub(crate) mass: InheritableVariable<f32>,
110
111 #[reflect(setter = "lock_rotations")]
112 pub(crate) rotation_locked: InheritableVariable<bool>,
113
114 #[reflect(setter = "lock_translation")]
115 pub(crate) translation_locked: InheritableVariable<bool>,
116
117 #[reflect(setter = "enable_ccd")]
118 pub(crate) ccd_enabled: InheritableVariable<bool>,
119
120 #[reflect(setter = "set_can_sleep")]
121 pub(crate) can_sleep: InheritableVariable<bool>,
122
123 #[reflect(setter = "set_dominance")]
124 pub(crate) dominance: InheritableVariable<i8>,
125
126 #[reflect(setter = "set_gravity_scale")]
127 pub(crate) gravity_scale: InheritableVariable<f32>,
128
129 #[visit(skip)]
130 #[reflect(hidden)]
131 pub(crate) sleeping: bool,
132
133 #[visit(skip)]
134 #[reflect(hidden)]
135 pub(crate) reset_forces: Cell<bool>,
136
137 #[visit(skip)]
138 #[reflect(hidden)]
139 pub(crate) native: Cell<RigidBodyHandle>,
140
141 #[visit(skip)]
142 #[reflect(hidden)]
143 pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
144}
145
146impl Debug for RigidBody {
147 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
148 write!(f, "RigidBody")
149 }
150}
151
152impl Default for RigidBody {
153 fn default() -> Self {
154 Self {
155 base: Default::default(),
156 lin_vel: Default::default(),
157 ang_vel: Default::default(),
158 lin_damping: Default::default(),
159 ang_damping: Default::default(),
160 sleeping: Default::default(),
161 body_type: InheritableVariable::new_modified(RigidBodyType::Dynamic),
162 mass: InheritableVariable::new_modified(1.0),
163 rotation_locked: Default::default(),
164 translation_locked: Default::default(),
165 ccd_enabled: Default::default(),
166 can_sleep: InheritableVariable::new_modified(true),
167 dominance: Default::default(),
168 gravity_scale: InheritableVariable::new_modified(1.0),
169 native: Cell::new(RigidBodyHandle::invalid()),
170 actions: Default::default(),
171 reset_forces: Default::default(),
172 }
173 }
174}
175
176impl Deref for RigidBody {
177 type Target = Base;
178
179 fn deref(&self) -> &Self::Target {
180 &self.base
181 }
182}
183
184impl DerefMut for RigidBody {
185 fn deref_mut(&mut self) -> &mut Self::Target {
186 &mut self.base
187 }
188}
189
190impl Clone for RigidBody {
191 fn clone(&self) -> Self {
192 Self {
193 base: self.base.clone(),
194 lin_vel: self.lin_vel.clone(),
195 ang_vel: self.ang_vel.clone(),
196 lin_damping: self.lin_damping.clone(),
197 ang_damping: self.ang_damping.clone(),
198 sleeping: self.sleeping,
199 body_type: self.body_type.clone(),
200 mass: self.mass.clone(),
201 rotation_locked: self.rotation_locked.clone(),
202 translation_locked: self.translation_locked.clone(),
203 ccd_enabled: self.ccd_enabled.clone(),
204 can_sleep: self.can_sleep.clone(),
205 dominance: self.dominance.clone(),
206 gravity_scale: self.gravity_scale.clone(),
207 native: Cell::new(RigidBodyHandle::invalid()),
209 actions: Default::default(),
210 reset_forces: self.reset_forces.clone(),
211 }
212 }
213}
214
215impl TypeUuidProvider for RigidBody {
216 fn type_uuid() -> Uuid {
217 uuid!("0b242335-75a4-4c65-9685-3e82a8979047")
218 }
219}
220
221impl RigidBody {
222 pub fn set_lin_vel(&mut self, lin_vel: Vector2<f32>) -> Vector2<f32> {
225 self.lin_vel.set_value_and_mark_modified(lin_vel)
226 }
227
228 pub fn lin_vel(&self) -> Vector2<f32> {
230 *self.lin_vel
231 }
232
233 pub fn set_ang_vel(&mut self, ang_vel: f32) -> f32 {
236 self.ang_vel.set_value_and_mark_modified(ang_vel)
237 }
238
239 pub fn ang_vel(&self) -> f32 {
241 *self.ang_vel
242 }
243
244 pub fn set_mass(&mut self, mass: f32) -> f32 {
247 self.mass.set_value_and_mark_modified(mass)
248 }
249
250 pub fn mass(&self) -> f32 {
252 *self.mass
253 }
254
255 pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
258 self.ang_damping.set_value_and_mark_modified(damping)
259 }
260
261 pub fn ang_damping(&self) -> f32 {
263 *self.ang_damping
264 }
265
266 pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
269 self.lin_damping.set_value_and_mark_modified(damping)
270 }
271
272 pub fn lin_damping(&self) -> f32 {
274 *self.lin_damping
275 }
276
277 pub fn lock_rotations(&mut self, state: bool) -> bool {
279 self.rotation_locked.set_value_and_mark_modified(state)
280 }
281
282 pub fn is_rotation_locked(&self) -> bool {
284 *self.rotation_locked
285 }
286
287 pub fn lock_translation(&mut self, state: bool) -> bool {
289 self.translation_locked.set_value_and_mark_modified(state)
290 }
291
292 pub fn is_translation_locked(&self) -> bool {
294 *self.translation_locked
295 }
296
297 pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
299 self.body_type.set_value_and_mark_modified(body_type)
300 }
301
302 pub fn body_type(&self) -> RigidBodyType {
304 *self.body_type
305 }
306
307 pub fn is_sleeping(&self) -> bool {
310 self.sleeping
311 }
312
313 pub fn is_ccd_enabled(&self) -> bool {
315 *self.ccd_enabled
316 }
317
318 pub fn enable_ccd(&mut self, enable: bool) -> bool {
321 self.ccd_enabled.set_value_and_mark_modified(enable)
322 }
323
324 pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
326 self.gravity_scale.set_value_and_mark_modified(scale)
327 }
328
329 pub fn gravity_scale(&self) -> f32 {
331 *self.gravity_scale
332 }
333
334 pub fn set_dominance(&mut self, dominance: i8) -> i8 {
339 self.dominance.set_value_and_mark_modified(dominance)
340 }
341
342 pub fn dominance(&self) -> i8 {
344 *self.dominance
345 }
346
347 pub fn apply_force(&mut self, force: Vector2<f32>) {
350 self.actions.get_mut().push_back(ApplyAction::Force(force))
351 }
352
353 pub fn apply_torque(&mut self, torque: f32) {
356 self.actions
357 .get_mut()
358 .push_back(ApplyAction::Torque(torque))
359 }
360
361 pub fn apply_force_at_point(&mut self, force: Vector2<f32>, point: Vector2<f32>) {
364 self.actions
365 .get_mut()
366 .push_back(ApplyAction::ForceAtPoint { force, point })
367 }
368
369 pub fn apply_impulse(&mut self, impulse: Vector2<f32>) {
372 self.actions
373 .get_mut()
374 .push_back(ApplyAction::Impulse(impulse))
375 }
376
377 pub fn apply_torque_impulse(&mut self, torque_impulse: f32) {
380 self.actions
381 .get_mut()
382 .push_back(ApplyAction::TorqueImpulse(torque_impulse))
383 }
384
385 pub fn apply_impulse_at_point(&mut self, impulse: Vector2<f32>, point: Vector2<f32>) {
389 self.actions
390 .get_mut()
391 .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
392 }
393
394 pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
397 self.can_sleep.set_value_and_mark_modified(can_sleep)
398 }
399
400 pub fn is_can_sleep(&self) -> bool {
402 *self.can_sleep
403 }
404
405 pub fn wake_up(&mut self) {
407 self.actions.get_mut().push_back(ApplyAction::WakeUp)
408 }
409
410 pub(crate) fn need_sync_model(&self) -> bool {
411 self.lin_vel.need_sync()
412 || self.ang_vel.need_sync()
413 || self.lin_damping.need_sync()
414 || self.ang_damping.need_sync()
415 || self.body_type.need_sync()
416 || self.mass.need_sync()
417 || self.rotation_locked.need_sync()
418 || self.translation_locked.need_sync()
419 || self.ccd_enabled.need_sync()
420 || self.can_sleep.need_sync()
421 || self.dominance.need_sync()
422 || self.gravity_scale.need_sync()
423 || self.reset_forces.get()
424 }
425}
426
427impl ConstructorProvider<Node, Graph> for RigidBody {
428 fn constructor() -> NodeConstructor {
429 NodeConstructor::new::<Self>()
430 .with_variant("Rigid Body", |_| {
431 RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body 2D"))
432 .build_node()
433 .into()
434 })
435 .with_group("Physics 2D")
436 }
437}
438
439impl NodeTrait for RigidBody {
440 fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
441 self.base.local_bounding_box()
442 }
443
444 fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
445 self.base.world_bounding_box()
446 }
447
448 fn id(&self) -> Uuid {
449 Self::type_uuid()
450 }
451
452 fn on_removed_from_graph(&mut self, graph: &mut Graph) {
453 graph.physics2d.remove_body(self.native.get());
454 self.native.set(RigidBodyHandle::invalid());
455
456 Log::info(format!(
457 "Native rigid body was removed for node: {}",
458 self.name()
459 ));
460 }
461
462 fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
463 context.physics2d.sync_to_rigid_body_node(self_handle, self);
464 }
465
466 fn on_global_transform_changed(
467 &self,
468 new_global_transform: &Matrix4<f32>,
469 context: &mut SyncContext,
470 ) {
471 if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
472 context
473 .physics2d
474 .set_rigid_body_position(self, new_global_transform);
475 }
476 }
477
478 fn update(&mut self, context: &mut UpdateContext) {
479 context.physics2d.sync_rigid_body_node(
480 self,
481 context
483 .nodes
484 .try_borrow(self.parent)
485 .map(|p| p.global_transform())
486 .unwrap_or_else(Matrix4::identity),
487 );
488 }
489
490 fn validate(&self, scene: &Scene) -> Result<(), String> {
491 for &child in self.children() {
492 if scene.graph.try_get_of_type::<Collider>(child).is_some() {
493 return Ok(());
494 }
495 }
496
497 Err("The 2D rigid body must have at least one 2D collider as a \
498 direct child node to work correctly!"
499 .to_string())
500 }
501}
502
503pub struct RigidBodyBuilder {
505 base_builder: BaseBuilder,
506 lin_vel: Vector2<f32>,
507 ang_vel: f32,
508 lin_damping: f32,
509 ang_damping: f32,
510 sleeping: bool,
511 body_type: RigidBodyType,
512 mass: f32,
513 rotation_locked: bool,
514 translation_locked: bool,
515 ccd_enabled: bool,
516 can_sleep: bool,
517 dominance: i8,
518 gravity_scale: f32,
519}
520
521impl RigidBodyBuilder {
522 pub fn new(base_builder: BaseBuilder) -> Self {
524 Self {
525 base_builder,
526 lin_vel: Default::default(),
527 ang_vel: Default::default(),
528 lin_damping: 0.0,
529 ang_damping: 0.0,
530 sleeping: false,
531 body_type: RigidBodyType::Dynamic,
532 mass: 1.0,
533 rotation_locked: false,
534 translation_locked: false,
535 ccd_enabled: false,
536 can_sleep: true,
537 dominance: 0,
538 gravity_scale: 1.0,
539 }
540 }
541
542 pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
544 self.body_type = body_type;
545 self
546 }
547
548 pub fn with_mass(mut self, mass: f32) -> Self {
550 self.mass = mass;
551 self
552 }
553
554 pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
556 self.ccd_enabled = enabled;
557 self
558 }
559
560 pub fn with_lin_vel(mut self, lin_vel: Vector2<f32>) -> Self {
562 self.lin_vel = lin_vel;
563 self
564 }
565
566 pub fn with_ang_vel(mut self, ang_vel: f32) -> Self {
568 self.ang_vel = ang_vel;
569 self
570 }
571
572 pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
574 self.ang_damping = ang_damping;
575 self
576 }
577
578 pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
580 self.lin_damping = lin_damping;
581 self
582 }
583
584 pub fn with_rotation_locked(mut self, rotation_locked: bool) -> Self {
586 self.rotation_locked = rotation_locked;
587 self
588 }
589
590 pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
592 self.translation_locked = translation_locked;
593 self
594 }
595
596 pub fn with_dominance(mut self, dominance: i8) -> Self {
598 self.dominance = dominance;
599 self
600 }
601
602 pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
604 self.gravity_scale = gravity_scale;
605 self
606 }
607
608 pub fn with_sleeping(mut self, sleeping: bool) -> Self {
610 self.sleeping = sleeping;
611 self
612 }
613
614 pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
616 self.can_sleep = can_sleep;
617 self
618 }
619
620 pub fn build_rigid_body(self) -> RigidBody {
622 RigidBody {
623 base: self.base_builder.build_base(),
624 lin_vel: self.lin_vel.into(),
625 ang_vel: self.ang_vel.into(),
626 lin_damping: self.lin_damping.into(),
627 ang_damping: self.ang_damping.into(),
628 sleeping: self.sleeping,
629 body_type: self.body_type.into(),
630 mass: self.mass.into(),
631 rotation_locked: self.rotation_locked.into(),
632 translation_locked: self.translation_locked.into(),
633 ccd_enabled: self.ccd_enabled.into(),
634 can_sleep: self.can_sleep.into(),
635 dominance: self.dominance.into(),
636 gravity_scale: self.gravity_scale.into(),
637 native: Cell::new(RigidBodyHandle::invalid()),
638 actions: Default::default(),
639 reset_forces: Default::default(),
640 }
641 }
642
643 pub fn build_node(self) -> Node {
645 Node::new(self.build_rigid_body())
646 }
647
648 pub fn build(self, graph: &mut Graph) -> Handle<Node> {
650 graph.add_node(self.build_node())
651 }
652}