fyrox_impl/scene/
rigidbody.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Rigid body is a physics entity that responsible for the dynamics and kinematics of the solid.
22//!
23//! # Common problems
24//!
25//! **Q:** Rigid body is "stuck".
26//! **A:** Most likely the rigid body is "sleeping", in this case it must be activated manually, it is
27//! most common problem with rigid bodies that controlled manually from code. They must be activated
28//! using [`RigidBody::wake_up`]. By default any external action does **not** wakes up rigid body.
29//! You can also explicitly tell to rigid body that it cannot sleep, by calling
30//! [`RigidBody::set_can_sleep`] with `false` value.
31use crate::scene::node::constructor::NodeConstructor;
32use crate::{
33    core::{
34        algebra::{Isometry3, Matrix4, UnitQuaternion, 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/// A set of possible types of rigid body.
66#[derive(
67    Copy, Clone, Debug, Reflect, Visit, PartialEq, Eq, Hash, AsRefStr, EnumString, VariantNames,
68)]
69#[repr(u32)]
70pub enum RigidBodyType {
71    /// Dynamic rigid bodies can be affected by external forces.
72    Dynamic = 0,
73    /// Static rigid bodies cannot be affected by external forces.
74    Static = 1,
75    /// Kinematic rigid body cannot be affected by external forces, but can push other rigid bodies.
76    /// It also does not have any dynamic, you are able to control the position manually.
77    KinematicPositionBased = 2,
78    /// Kinematic rigid body cannot be affected by external forces, but can push other rigid bodies.
79    /// It also does not have any dynamic, you are able to control the position by changing velocity.
80    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    NextTranslation(Vector3<f32>),
148    NextRotation(UnitQuaternion<f32>),
149    NextPosition(Isometry3<f32>),
150}
151
152#[derive(Copy, Clone, Debug, Reflect, Visit, PartialEq, AsRefStr, EnumString, VariantNames)]
153/// Possible types of rigidbody mass properties
154pub enum RigidBodyMassPropertiesType {
155    /// Use default mass properties
156    Default,
157    /// Use additional mass properties
158    Additional {
159        /// Local to rigidbody center of mass
160        center_of_mass: Vector3<f32>,
161        /// Resistance of the rigid-body wrt. the angular movements
162        principal_inertia: Vector3<f32>,
163    },
164}
165uuid_provider!(RigidBodyMassPropertiesType = "663b6a92-9c0f-4f47-b66a-6b4293312a5d");
166
167/// Rigid body is a physics entity that responsible for the dynamics and kinematics of the solid.
168/// Use this node when you need to simulate real-world physics in your game.
169///
170/// # Sleeping
171///
172/// Rigid body that does not move for some time will go asleep. This means that the body will not
173/// move unless it is woken up by some other moving body. This feature allows to save CPU resources.
174#[derive(Visit, Reflect, ComponentProvider)]
175#[reflect(derived_type = "Node")]
176pub struct RigidBody {
177    base: Base,
178
179    #[reflect(setter = "set_lin_vel")]
180    pub(crate) lin_vel: InheritableVariable<Vector3<f32>>,
181
182    #[reflect(setter = "set_ang_vel")]
183    pub(crate) ang_vel: InheritableVariable<Vector3<f32>>,
184
185    #[reflect(setter = "set_lin_damping")]
186    pub(crate) lin_damping: InheritableVariable<f32>,
187
188    #[reflect(setter = "set_ang_damping")]
189    pub(crate) ang_damping: InheritableVariable<f32>,
190
191    #[reflect(setter = "set_body_type")]
192    pub(crate) body_type: InheritableVariable<RigidBodyType>,
193
194    #[reflect(min_value = 0.0, step = 0.05)]
195    #[reflect(setter = "set_mass")]
196    pub(crate) mass: InheritableVariable<f32>,
197
198    #[reflect(setter = "lock_x_rotations")]
199    pub(crate) x_rotation_locked: InheritableVariable<bool>,
200
201    #[reflect(setter = "lock_y_rotations")]
202    pub(crate) y_rotation_locked: InheritableVariable<bool>,
203
204    #[reflect(setter = "lock_z_rotations")]
205    pub(crate) z_rotation_locked: InheritableVariable<bool>,
206
207    #[reflect(setter = "lock_translation")]
208    pub(crate) translation_locked: InheritableVariable<bool>,
209
210    #[reflect(setter = "enable_ccd")]
211    pub(crate) ccd_enabled: InheritableVariable<bool>,
212
213    #[reflect(setter = "set_can_sleep")]
214    pub(crate) can_sleep: InheritableVariable<bool>,
215
216    #[reflect(setter = "set_dominance")]
217    pub(crate) dominance: InheritableVariable<i8>,
218
219    #[reflect(setter = "set_gravity_scale")]
220    pub(crate) gravity_scale: InheritableVariable<f32>,
221
222    #[visit(optional)]
223    #[reflect(setter = "set_mass_properties_type")]
224    pub(crate) mass_properties_type: InheritableVariable<RigidBodyMassPropertiesType>,
225
226    #[visit(skip)]
227    #[reflect(hidden)]
228    pub(crate) sleeping: bool,
229    #[visit(skip)]
230    #[reflect(hidden)]
231    pub(crate) reset_forces: Cell<bool>,
232    #[visit(skip)]
233    #[reflect(hidden)]
234    pub(crate) native: Cell<RigidBodyHandle>,
235    #[visit(skip)]
236    #[reflect(hidden)]
237    pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
238}
239
240impl Debug for RigidBody {
241    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
242        write!(f, "RigidBody")
243    }
244}
245
246impl Default for RigidBody {
247    fn default() -> Self {
248        Self {
249            base: Default::default(),
250            lin_vel: Default::default(),
251            ang_vel: Default::default(),
252            lin_damping: Default::default(),
253            ang_damping: Default::default(),
254            sleeping: Default::default(),
255            body_type: InheritableVariable::new_modified(RigidBodyType::Dynamic),
256            mass: InheritableVariable::new_modified(1.0),
257            x_rotation_locked: Default::default(),
258            y_rotation_locked: Default::default(),
259            z_rotation_locked: Default::default(),
260            translation_locked: Default::default(),
261            ccd_enabled: Default::default(),
262            can_sleep: InheritableVariable::new_modified(true),
263            dominance: Default::default(),
264            gravity_scale: InheritableVariable::new_modified(1.0),
265            native: Cell::new(RigidBodyHandle::invalid()),
266            actions: Default::default(),
267            reset_forces: Default::default(),
268            mass_properties_type: InheritableVariable::new_modified(
269                RigidBodyMassPropertiesType::Default,
270            ),
271        }
272    }
273}
274
275impl Deref for RigidBody {
276    type Target = Base;
277
278    fn deref(&self) -> &Self::Target {
279        &self.base
280    }
281}
282
283impl DerefMut for RigidBody {
284    fn deref_mut(&mut self) -> &mut Self::Target {
285        &mut self.base
286    }
287}
288
289impl Clone for RigidBody {
290    fn clone(&self) -> Self {
291        Self {
292            base: self.base.clone(),
293            lin_vel: self.lin_vel.clone(),
294            ang_vel: self.ang_vel.clone(),
295            lin_damping: self.lin_damping.clone(),
296            ang_damping: self.ang_damping.clone(),
297            sleeping: self.sleeping,
298            body_type: self.body_type.clone(),
299            mass: self.mass.clone(),
300            x_rotation_locked: self.x_rotation_locked.clone(),
301            y_rotation_locked: self.y_rotation_locked.clone(),
302            z_rotation_locked: self.z_rotation_locked.clone(),
303            translation_locked: self.translation_locked.clone(),
304            ccd_enabled: self.ccd_enabled.clone(),
305            can_sleep: self.can_sleep.clone(),
306            dominance: self.dominance.clone(),
307            gravity_scale: self.gravity_scale.clone(),
308            // Do not copy. The copy will have its own native representation.
309            native: Cell::new(RigidBodyHandle::invalid()),
310            actions: Default::default(),
311            reset_forces: self.reset_forces.clone(),
312            mass_properties_type: self.mass_properties_type.clone(),
313        }
314    }
315}
316
317impl TypeUuidProvider for RigidBody {
318    fn type_uuid() -> Uuid {
319        uuid!("4be15a7c-3566-49c4-bba8-2f4ccc57ffed")
320    }
321}
322
323impl RigidBody {
324    /// Sets new linear velocity of the rigid body. Changing this parameter will wake up the rigid
325    /// body!
326    pub fn set_lin_vel(&mut self, lin_vel: Vector3<f32>) -> Vector3<f32> {
327        self.lin_vel.set_value_and_mark_modified(lin_vel)
328    }
329
330    /// Returns current linear velocity of the rigid body.
331    pub fn lin_vel(&self) -> Vector3<f32> {
332        *self.lin_vel
333    }
334
335    /// Sets new angular velocity of the rigid body. Changing this parameter will wake up the rigid
336    /// body!
337    pub fn set_ang_vel(&mut self, ang_vel: Vector3<f32>) -> Vector3<f32> {
338        self.ang_vel.set_value_and_mark_modified(ang_vel)
339    }
340
341    /// Returns current angular velocity of the rigid body.
342    pub fn ang_vel(&self) -> Vector3<f32> {
343        *self.ang_vel
344    }
345
346    /// Sets _additional_ mass of the rigid body. It is called additional because real mass is defined
347    /// by colliders attached to the body and their density and volume.
348    pub fn set_mass(&mut self, mass: f32) -> f32 {
349        self.mass.set_value_and_mark_modified(mass)
350    }
351
352    /// Returns _additional_ mass of the rigid body.
353    pub fn mass(&self) -> f32 {
354        *self.mass
355    }
356
357    /// Sets angular damping of the rigid body. Angular damping will decrease angular velocity over
358    /// time. Default is zero.
359    pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
360        self.ang_damping.set_value_and_mark_modified(damping)
361    }
362
363    /// Returns current angular damping.
364    pub fn ang_damping(&self) -> f32 {
365        *self.ang_damping
366    }
367
368    /// Sets linear damping of the rigid body. Linear damping will decrease linear velocity over
369    /// time. Default is zero.
370    pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
371        self.lin_damping.set_value_and_mark_modified(damping)
372    }
373
374    /// Returns current linear damping.
375    pub fn lin_damping(&self) -> f32 {
376        *self.lin_damping
377    }
378
379    /// Locks rotations around X axis in world coordinates.
380    pub fn lock_x_rotations(&mut self, state: bool) -> bool {
381        self.x_rotation_locked.set_value_and_mark_modified(state)
382    }
383
384    /// Returns true if rotation around X axis is locked, false - otherwise.
385    pub fn is_x_rotation_locked(&self) -> bool {
386        *self.x_rotation_locked
387    }
388
389    /// Locks rotations around Y axis in world coordinates.
390    pub fn lock_y_rotations(&mut self, state: bool) -> bool {
391        self.y_rotation_locked.set_value_and_mark_modified(state)
392    }
393
394    /// Returns true if rotation around Y axis is locked, false - otherwise.
395    pub fn is_y_rotation_locked(&self) -> bool {
396        *self.y_rotation_locked
397    }
398
399    /// Locks rotations around Z axis in world coordinates.
400    pub fn lock_z_rotations(&mut self, state: bool) -> bool {
401        self.z_rotation_locked.set_value_and_mark_modified(state)
402    }
403
404    /// Returns true if rotation around Z axis is locked, false - otherwise.
405    pub fn is_z_rotation_locked(&self) -> bool {
406        *self.z_rotation_locked
407    }
408
409    /// Locks or unlocks rotations around all axes at once.
410    pub fn lock_rotations(&mut self, locked: bool) {
411        self.x_rotation_locked.set_value_and_mark_modified(locked);
412        self.y_rotation_locked.set_value_and_mark_modified(locked);
413        self.z_rotation_locked.set_value_and_mark_modified(locked);
414    }
415
416    /// Locks translation in world coordinates.
417    pub fn lock_translation(&mut self, state: bool) -> bool {
418        self.translation_locked.set_value_and_mark_modified(state)
419    }
420
421    /// Returns true if translation is locked, false - otherwise.
422    pub fn is_translation_locked(&self) -> bool {
423        *self.translation_locked
424    }
425
426    /// Sets new body type. See [`RigidBodyType`] for more info.
427    pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
428        self.body_type.set_value_and_mark_modified(body_type)
429    }
430
431    /// Returns current body type.
432    pub fn body_type(&self) -> RigidBodyType {
433        *self.body_type
434    }
435
436    /// Returns true if the rigid body is sleeping (temporarily excluded from simulation to save
437    /// resources), false - otherwise.
438    pub fn is_sleeping(&self) -> bool {
439        self.sleeping
440    }
441
442    /// Returns true if continuous collision detection is enabled, false - otherwise.
443    pub fn is_ccd_enabled(&self) -> bool {
444        *self.ccd_enabled
445    }
446
447    /// Enables or disables continuous collision detection. CCD is very useful for fast moving objects
448    /// to prevent accidental penetrations on high velocities.
449    pub fn enable_ccd(&mut self, enable: bool) -> bool {
450        self.ccd_enabled.set_value_and_mark_modified(enable)
451    }
452
453    /// Sets a gravity scale coefficient. Zero can be used to disable gravity.
454    pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
455        self.gravity_scale.set_value_and_mark_modified(scale)
456    }
457
458    /// Sets mass properties type.
459    pub fn set_mass_properties_type(
460        &mut self,
461        mass_properties_type: RigidBodyMassPropertiesType,
462    ) -> RigidBodyMassPropertiesType {
463        self.mass_properties_type
464            .set_value_and_mark_modified(mass_properties_type)
465    }
466
467    /// Returns current mass properties type.
468    pub fn mass_properties_type(&self) -> RigidBodyMassPropertiesType {
469        *self.mass_properties_type
470    }
471
472    /// Returns current gravity scale coefficient.
473    pub fn gravity_scale(&self) -> f32 {
474        *self.gravity_scale
475    }
476
477    /// Sets dominance group of the rigid body. A rigid body with higher dominance group will not
478    /// be affected by an object with lower dominance group (it will behave like it has an infinite
479    /// mass). This is very importance feature for character physics in games, you can set highest
480    /// dominance group to the player, and it won't be affected by any external forces.
481    pub fn set_dominance(&mut self, dominance: i8) -> i8 {
482        self.dominance.set_value_and_mark_modified(dominance)
483    }
484
485    /// Returns current dominance group.
486    pub fn dominance(&self) -> i8 {
487        *self.dominance
488    }
489
490    /// Applies a force at the center-of-mass of this rigid-body. The force will be applied in the
491    /// next simulation step. This does nothing on non-dynamic bodies.
492    pub fn apply_force(&mut self, force: Vector3<f32>) {
493        self.actions.get_mut().push_back(ApplyAction::Force(force))
494    }
495
496    /// Applies a torque at the center-of-mass of this rigid-body. The torque will be applied in
497    /// the next simulation step. This does nothing on non-dynamic bodies.
498    pub fn apply_torque(&mut self, torque: Vector3<f32>) {
499        self.actions
500            .get_mut()
501            .push_back(ApplyAction::Torque(torque))
502    }
503
504    /// Applies a force at the given world-space point of this rigid-body. The force will be applied
505    /// in the next simulation step. This does nothing on non-dynamic bodies.
506    pub fn apply_force_at_point(&mut self, force: Vector3<f32>, point: Vector3<f32>) {
507        self.actions
508            .get_mut()
509            .push_back(ApplyAction::ForceAtPoint { force, point })
510    }
511
512    /// Applies an impulse at the center-of-mass of this rigid-body. The impulse is applied right
513    /// away, changing the linear velocity. This does nothing on non-dynamic bodies.
514    pub fn apply_impulse(&mut self, impulse: Vector3<f32>) {
515        self.actions
516            .get_mut()
517            .push_back(ApplyAction::Impulse(impulse))
518    }
519
520    /// Applies an angular impulse at the center-of-mass of this rigid-body. The impulse is applied
521    /// right away, changing the angular velocity. This does nothing on non-dynamic bodies.
522    pub fn apply_torque_impulse(&mut self, torque_impulse: Vector3<f32>) {
523        self.actions
524            .get_mut()
525            .push_back(ApplyAction::TorqueImpulse(torque_impulse))
526    }
527
528    /// Applies an impulse at the given world-space point of this rigid-body. The impulse is applied
529    /// right away, changing the linear and/or angular velocities. This does nothing on non-dynamic
530    /// bodies.
531    pub fn apply_impulse_at_point(&mut self, impulse: Vector3<f32>, point: Vector3<f32>) {
532        self.actions
533            .get_mut()
534            .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
535    }
536
537    /// If this rigid body is kinematic, sets its future translation after
538    /// the next timestep integration.
539    pub fn set_next_kinematic_translation(&mut self, translation: Vector3<f32>) {
540        self.actions
541            .get_mut()
542            .push_back(ApplyAction::NextTranslation(translation));
543    }
544
545    /// If this rigid body is kinematic, sets its future orientation after
546    /// the next timestep integration.
547    pub fn set_next_kinematic_rotation(&mut self, rotation: UnitQuaternion<f32>) {
548        self.actions
549            .get_mut()
550            .push_back(ApplyAction::NextRotation(rotation));
551    }
552
553    /// If this rigid body is kinematic, sets its future position (translation and orientation) after
554    /// the next timestep integration.
555    pub fn set_next_kinematic_position(&mut self, position: Isometry3<f32>) {
556        self.actions
557            .get_mut()
558            .push_back(ApplyAction::NextPosition(position));
559    }
560
561    /// Sets whether the rigid body can sleep or not. If `false` is passed, it _automatically_ wake
562    /// up rigid body.
563    pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
564        self.can_sleep.set_value_and_mark_modified(can_sleep)
565    }
566
567    /// Returns true if the rigid body can sleep, false - otherwise.
568    pub fn is_can_sleep(&self) -> bool {
569        *self.can_sleep
570    }
571
572    /// Wakes up rigid body, forcing it to return to participate in the simulation.
573    pub fn wake_up(&mut self) {
574        self.actions.get_mut().push_back(ApplyAction::WakeUp)
575    }
576
577    pub(crate) fn need_sync_model(&self) -> bool {
578        self.lin_vel.need_sync()
579            || self.ang_vel.need_sync()
580            || self.lin_damping.need_sync()
581            || self.ang_damping.need_sync()
582            || self.body_type.need_sync()
583            || self.mass.need_sync()
584            || self.x_rotation_locked.need_sync()
585            || self.y_rotation_locked.need_sync()
586            || self.z_rotation_locked.need_sync()
587            || self.translation_locked.need_sync()
588            || self.ccd_enabled.need_sync()
589            || self.can_sleep.need_sync()
590            || self.dominance.need_sync()
591            || self.gravity_scale.need_sync()
592            || self.reset_forces.get()
593    }
594}
595
596impl ConstructorProvider<Node, Graph> for RigidBody {
597    fn constructor() -> NodeConstructor {
598        NodeConstructor::new::<Self>()
599            .with_variant("Rigid Body", |_| {
600                RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body"))
601                    .build_node()
602                    .into()
603            })
604            .with_group("Physics")
605    }
606}
607
608impl NodeTrait for RigidBody {
609    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
610        self.base.local_bounding_box()
611    }
612
613    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
614        self.base.world_bounding_box()
615    }
616
617    fn id(&self) -> Uuid {
618        Self::type_uuid()
619    }
620
621    fn on_removed_from_graph(&mut self, graph: &mut Graph) {
622        graph.physics.remove_body(self.native.get());
623        self.native.set(RigidBodyHandle::invalid());
624
625        Log::info(format!(
626            "Native rigid body was removed for node: {}",
627            self.name()
628        ));
629    }
630
631    fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
632        context.physics.sync_to_rigid_body_node(self_handle, self);
633    }
634
635    fn on_global_transform_changed(
636        &self,
637        new_global_transform: &Matrix4<f32>,
638        context: &mut SyncContext,
639    ) {
640        if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
641            context
642                .physics
643                .set_rigid_body_position(self, new_global_transform);
644        }
645    }
646
647    fn update(&mut self, context: &mut UpdateContext) {
648        context.physics.sync_rigid_body_node(
649            self,
650            // Rigid body can be root node of a scene, in this case it does not have a parent.
651            context
652                .nodes
653                .try_borrow(self.parent)
654                .map(|p| p.global_transform())
655                .unwrap_or_else(Matrix4::identity),
656        );
657    }
658
659    fn validate(&self, scene: &Scene) -> Result<(), String> {
660        for &child in self.children() {
661            if scene.graph.try_get_of_type::<Collider>(child).is_some() {
662                return Ok(());
663            }
664        }
665
666        Err("The 3D rigid body must have at least one 3D collider as a \
667        direct child node to work correctly!"
668            .to_string())
669    }
670}
671
672/// Allows you to create rigid body in declarative manner.
673pub struct RigidBodyBuilder {
674    base_builder: BaseBuilder,
675    lin_vel: Vector3<f32>,
676    ang_vel: Vector3<f32>,
677    lin_damping: f32,
678    ang_damping: f32,
679    sleeping: bool,
680    body_type: RigidBodyType,
681    mass: f32,
682    x_rotation_locked: bool,
683    y_rotation_locked: bool,
684    z_rotation_locked: bool,
685    translation_locked: bool,
686    ccd_enabled: bool,
687    can_sleep: bool,
688    dominance: i8,
689    gravity_scale: f32,
690    mass_properties_type: RigidBodyMassPropertiesType,
691}
692
693impl RigidBodyBuilder {
694    /// Creates new rigid body builder.
695    pub fn new(base_builder: BaseBuilder) -> Self {
696        Self {
697            base_builder,
698            lin_vel: Default::default(),
699            ang_vel: Default::default(),
700            lin_damping: 0.0,
701            ang_damping: 0.0,
702            sleeping: false,
703            body_type: RigidBodyType::Dynamic,
704            mass: 1.0,
705            x_rotation_locked: false,
706            y_rotation_locked: false,
707            z_rotation_locked: false,
708            translation_locked: false,
709            ccd_enabled: false,
710            can_sleep: true,
711            dominance: 0,
712            gravity_scale: 1.0,
713            mass_properties_type: RigidBodyMassPropertiesType::Default,
714        }
715    }
716
717    /// Sets the desired body type.
718    pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
719        self.body_type = body_type;
720        self
721    }
722
723    /// Sets the desired _additional_ mass of the body.
724    pub fn with_mass(mut self, mass: f32) -> Self {
725        self.mass = mass;
726        self
727    }
728
729    /// Sets whether continuous collision detection should be enabled or not.
730    pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
731        self.ccd_enabled = enabled;
732        self
733    }
734
735    /// Sets desired linear velocity.
736    pub fn with_lin_vel(mut self, lin_vel: Vector3<f32>) -> Self {
737        self.lin_vel = lin_vel;
738        self
739    }
740
741    /// Sets desired angular velocity.
742    pub fn with_ang_vel(mut self, ang_vel: Vector3<f32>) -> Self {
743        self.ang_vel = ang_vel;
744        self
745    }
746
747    /// Sets desired angular damping.
748    pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
749        self.ang_damping = ang_damping;
750        self
751    }
752
753    /// Sets desired linear damping.
754    pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
755        self.lin_damping = lin_damping;
756        self
757    }
758
759    /// Sets whether the rotation around X axis of the body should be locked or not.
760    pub fn with_x_rotation_locked(mut self, x_rotation_locked: bool) -> Self {
761        self.x_rotation_locked = x_rotation_locked;
762        self
763    }
764
765    /// Sets whether the rotation around Y axis of the body should be locked or not.
766    pub fn with_y_rotation_locked(mut self, y_rotation_locked: bool) -> Self {
767        self.y_rotation_locked = y_rotation_locked;
768        self
769    }
770
771    /// Sets whether the rotation around Z axis of the body should be locked or not.
772    pub fn with_z_rotation_locked(mut self, z_rotation_locked: bool) -> Self {
773        self.z_rotation_locked = z_rotation_locked;
774        self
775    }
776
777    /// Sets whether the translation of the body should be locked or not.
778    pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
779        self.translation_locked = translation_locked;
780        self
781    }
782
783    /// Locks or unlocks rotations of the rigid body.
784    pub fn with_locked_rotations(mut self, locked: bool) -> Self {
785        self.x_rotation_locked = locked;
786        self.y_rotation_locked = locked;
787        self.z_rotation_locked = locked;
788        self
789    }
790
791    /// Sets initial state of the body (sleeping or not).
792    pub fn with_sleeping(mut self, sleeping: bool) -> Self {
793        self.sleeping = sleeping;
794        self
795    }
796
797    /// Sets whether rigid body can sleep or not.
798    pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
799        self.can_sleep = can_sleep;
800        self
801    }
802
803    /// Sets desired dominance group.
804    pub fn with_dominance(mut self, dominance: i8) -> Self {
805        self.dominance = dominance;
806        self
807    }
808
809    /// Sets desired gravity scale.
810    pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
811        self.gravity_scale = gravity_scale;
812        self
813    }
814
815    /// Sets mass properties type.
816    pub fn with_mass_properties_type(
817        mut self,
818        mass_properties_type: RigidBodyMassPropertiesType,
819    ) -> Self {
820        self.mass_properties_type = mass_properties_type;
821        self
822    }
823
824    /// Creates RigidBody node but does not add it to the graph.
825    pub fn build_rigid_body(self) -> RigidBody {
826        RigidBody {
827            base: self.base_builder.build_base(),
828            lin_vel: self.lin_vel.into(),
829            ang_vel: self.ang_vel.into(),
830            lin_damping: self.lin_damping.into(),
831            ang_damping: self.ang_damping.into(),
832            sleeping: self.sleeping,
833            body_type: self.body_type.into(),
834            mass: self.mass.into(),
835            x_rotation_locked: self.x_rotation_locked.into(),
836            y_rotation_locked: self.y_rotation_locked.into(),
837            z_rotation_locked: self.z_rotation_locked.into(),
838            translation_locked: self.translation_locked.into(),
839            ccd_enabled: self.ccd_enabled.into(),
840            can_sleep: self.can_sleep.into(),
841            dominance: self.dominance.into(),
842            gravity_scale: self.gravity_scale.into(),
843            native: Cell::new(RigidBodyHandle::invalid()),
844            actions: Default::default(),
845            reset_forces: Default::default(),
846            mass_properties_type: self.mass_properties_type.into(),
847        }
848    }
849
850    /// Creates RigidBody node but does not add it to the graph.
851    pub fn build_node(self) -> Node {
852        Node::new(self.build_rigid_body())
853    }
854
855    /// Creates RigidBody node and adds it to the graph.
856    pub fn build(self, graph: &mut Graph) -> Handle<Node> {
857        graph.add_node(self.build_node())
858    }
859}