Skip to main content

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::collider::ColliderShape;
32use crate::scene::node::constructor::NodeConstructor;
33use crate::{
34    core::{
35        algebra::{Isometry3, Matrix4, UnitQuaternion, Vector3},
36        log::Log,
37        math::{aabb::AxisAlignedBoundingBox, m4x4_approx_eq},
38        parking_lot::Mutex,
39        pool::Handle,
40        reflect::prelude::*,
41        type_traits::prelude::*,
42        uuid::{uuid, Uuid},
43        variable::InheritableVariable,
44        visitor::prelude::*,
45    },
46    scene::{
47        base::{Base, BaseBuilder},
48        collider::Collider,
49        graph::Graph,
50        node::{Node, NodeTrait, SyncContext, UpdateContext},
51        Scene,
52    },
53};
54use fyrox_core::uuid_provider;
55use fyrox_graph::constructor::ConstructorProvider;
56use fyrox_graph::SceneGraph;
57use rapier3d::{dynamics, prelude::RigidBodyHandle};
58use std::{
59    cell::Cell,
60    collections::VecDeque,
61    fmt::{Debug, Formatter},
62    ops::{Deref, DerefMut},
63};
64use strum_macros::{AsRefStr, EnumString, VariantNames};
65
66/// A set of possible types of rigid body.
67#[derive(
68    Copy, Clone, Debug, Reflect, Visit, PartialEq, Eq, Hash, AsRefStr, EnumString, VariantNames,
69)]
70#[repr(u32)]
71#[derive(Default)]
72pub enum RigidBodyType {
73    /// Dynamic rigid bodies can be affected by external forces.
74    #[default]
75    Dynamic = 0,
76    /// Static rigid bodies cannot be affected by external forces.
77    Static = 1,
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 manually.
80    KinematicPositionBased = 2,
81    /// Kinematic rigid body cannot be affected by external forces, but can push other rigid bodies.
82    /// It also does not have any dynamic, you are able to control the position by changing velocity.
83    KinematicVelocityBased = 3,
84}
85
86uuid_provider!(RigidBodyType = "562d2907-1b41-483a-8ca2-12eebaff7f5d");
87
88impl From<dynamics::RigidBodyType> for RigidBodyType {
89    fn from(s: dynamics::RigidBodyType) -> Self {
90        match s {
91            dynamics::RigidBodyType::Dynamic => Self::Dynamic,
92            dynamics::RigidBodyType::Fixed => Self::Static,
93            dynamics::RigidBodyType::KinematicPositionBased => Self::KinematicPositionBased,
94            dynamics::RigidBodyType::KinematicVelocityBased => Self::KinematicVelocityBased,
95        }
96    }
97}
98
99impl From<RigidBodyType> for rapier3d::dynamics::RigidBodyType {
100    fn from(v: RigidBodyType) -> Self {
101        match v {
102            RigidBodyType::Dynamic => rapier3d::dynamics::RigidBodyType::Dynamic,
103            RigidBodyType::Static => rapier3d::dynamics::RigidBodyType::Fixed,
104            RigidBodyType::KinematicPositionBased => {
105                rapier3d::dynamics::RigidBodyType::KinematicPositionBased
106            }
107            RigidBodyType::KinematicVelocityBased => {
108                rapier3d::dynamics::RigidBodyType::KinematicVelocityBased
109            }
110        }
111    }
112}
113
114impl From<RigidBodyType> for rapier2d::dynamics::RigidBodyType {
115    fn from(v: RigidBodyType) -> Self {
116        match v {
117            RigidBodyType::Dynamic => rapier2d::dynamics::RigidBodyType::Dynamic,
118            RigidBodyType::Static => rapier2d::dynamics::RigidBodyType::Fixed,
119            RigidBodyType::KinematicPositionBased => {
120                rapier2d::dynamics::RigidBodyType::KinematicPositionBased
121            }
122            RigidBodyType::KinematicVelocityBased => {
123                rapier2d::dynamics::RigidBodyType::KinematicVelocityBased
124            }
125        }
126    }
127}
128
129#[derive(Debug)]
130pub(crate) enum ApplyAction {
131    Force(Vector3<f32>),
132    Torque(Vector3<f32>),
133    ForceAtPoint {
134        force: Vector3<f32>,
135        point: Vector3<f32>,
136    },
137    Impulse(Vector3<f32>),
138    TorqueImpulse(Vector3<f32>),
139    ImpulseAtPoint {
140        impulse: Vector3<f32>,
141        point: Vector3<f32>,
142    },
143    WakeUp,
144    NextTranslation(Vector3<f32>),
145    NextRotation(UnitQuaternion<f32>),
146    NextPosition(Isometry3<f32>),
147}
148
149#[derive(Copy, Clone, Debug, Reflect, Visit, PartialEq, AsRefStr, EnumString, VariantNames)]
150/// Possible types of rigidbody mass properties
151pub enum RigidBodyMassPropertiesType {
152    /// Use default mass properties
153    Default,
154    /// Use additional mass properties
155    Additional {
156        /// Local to rigidbody center of mass
157        center_of_mass: Vector3<f32>,
158        /// Resistance of the rigid-body wrt. the angular movements
159        principal_inertia: Vector3<f32>,
160    },
161}
162uuid_provider!(RigidBodyMassPropertiesType = "663b6a92-9c0f-4f47-b66a-6b4293312a5d");
163
164/// Rigid body is a physics entity that responsible for the dynamics and kinematics of the solid.
165/// Use this node when you need to simulate real-world physics in your game.
166///
167/// # Sleeping
168///
169/// Rigid body that does not move for some time will go asleep. This means that the body will not
170/// move unless it is woken up by some other moving body. This feature allows to save CPU resources.
171#[derive(Visit, Reflect, ComponentProvider)]
172#[reflect(derived_type = "Node")]
173pub struct RigidBody {
174    base: Base,
175
176    #[reflect(setter = "set_lin_vel")]
177    pub(crate) lin_vel: InheritableVariable<Vector3<f32>>,
178
179    #[reflect(setter = "set_ang_vel")]
180    pub(crate) ang_vel: InheritableVariable<Vector3<f32>>,
181
182    #[reflect(setter = "set_lin_damping")]
183    pub(crate) lin_damping: InheritableVariable<f32>,
184
185    #[reflect(setter = "set_ang_damping")]
186    pub(crate) ang_damping: InheritableVariable<f32>,
187
188    #[reflect(setter = "set_body_type")]
189    pub(crate) body_type: InheritableVariable<RigidBodyType>,
190
191    #[reflect(min_value = 0.0, step = 0.05)]
192    #[reflect(setter = "set_mass")]
193    pub(crate) mass: InheritableVariable<f32>,
194
195    #[reflect(setter = "lock_x_rotations")]
196    pub(crate) x_rotation_locked: InheritableVariable<bool>,
197
198    #[reflect(setter = "lock_y_rotations")]
199    pub(crate) y_rotation_locked: InheritableVariable<bool>,
200
201    #[reflect(setter = "lock_z_rotations")]
202    pub(crate) z_rotation_locked: InheritableVariable<bool>,
203
204    #[reflect(setter = "lock_translation")]
205    pub(crate) translation_locked: InheritableVariable<bool>,
206
207    #[reflect(setter = "enable_ccd")]
208    pub(crate) ccd_enabled: InheritableVariable<bool>,
209
210    #[reflect(setter = "set_can_sleep")]
211    pub(crate) can_sleep: InheritableVariable<bool>,
212
213    #[reflect(setter = "set_dominance")]
214    pub(crate) dominance: InheritableVariable<i8>,
215
216    #[reflect(setter = "set_gravity_scale")]
217    pub(crate) gravity_scale: InheritableVariable<f32>,
218
219    #[visit(optional)]
220    #[reflect(setter = "set_mass_properties_type")]
221    pub(crate) mass_properties_type: InheritableVariable<RigidBodyMassPropertiesType>,
222
223    #[visit(skip)]
224    #[reflect(hidden)]
225    pub(crate) sleeping: bool,
226    #[visit(skip)]
227    #[reflect(hidden)]
228    pub(crate) reset_forces: Cell<bool>,
229    #[visit(skip)]
230    #[reflect(hidden)]
231    pub(crate) native: Cell<RigidBodyHandle>,
232    #[visit(skip)]
233    #[reflect(hidden)]
234    pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
235}
236
237impl Debug for RigidBody {
238    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
239        write!(f, "RigidBody")
240    }
241}
242
243impl Default for RigidBody {
244    fn default() -> Self {
245        Self {
246            base: Default::default(),
247            lin_vel: Default::default(),
248            ang_vel: Default::default(),
249            lin_damping: Default::default(),
250            ang_damping: Default::default(),
251            sleeping: Default::default(),
252            body_type: InheritableVariable::new_modified(RigidBodyType::Dynamic),
253            mass: InheritableVariable::new_modified(1.0),
254            x_rotation_locked: Default::default(),
255            y_rotation_locked: Default::default(),
256            z_rotation_locked: Default::default(),
257            translation_locked: Default::default(),
258            ccd_enabled: Default::default(),
259            can_sleep: InheritableVariable::new_modified(true),
260            dominance: Default::default(),
261            gravity_scale: InheritableVariable::new_modified(1.0),
262            native: Cell::new(RigidBodyHandle::invalid()),
263            actions: Default::default(),
264            reset_forces: Default::default(),
265            mass_properties_type: InheritableVariable::new_modified(
266                RigidBodyMassPropertiesType::Default,
267            ),
268        }
269    }
270}
271
272impl Deref for RigidBody {
273    type Target = Base;
274
275    fn deref(&self) -> &Self::Target {
276        &self.base
277    }
278}
279
280impl DerefMut for RigidBody {
281    fn deref_mut(&mut self) -> &mut Self::Target {
282        &mut self.base
283    }
284}
285
286impl Clone for RigidBody {
287    fn clone(&self) -> Self {
288        Self {
289            base: self.base.clone(),
290            lin_vel: self.lin_vel.clone(),
291            ang_vel: self.ang_vel.clone(),
292            lin_damping: self.lin_damping.clone(),
293            ang_damping: self.ang_damping.clone(),
294            sleeping: self.sleeping,
295            body_type: self.body_type.clone(),
296            mass: self.mass.clone(),
297            x_rotation_locked: self.x_rotation_locked.clone(),
298            y_rotation_locked: self.y_rotation_locked.clone(),
299            z_rotation_locked: self.z_rotation_locked.clone(),
300            translation_locked: self.translation_locked.clone(),
301            ccd_enabled: self.ccd_enabled.clone(),
302            can_sleep: self.can_sleep.clone(),
303            dominance: self.dominance.clone(),
304            gravity_scale: self.gravity_scale.clone(),
305            // Do not copy. The copy will have its own native representation.
306            native: Cell::new(RigidBodyHandle::invalid()),
307            actions: Default::default(),
308            reset_forces: self.reset_forces.clone(),
309            mass_properties_type: self.mass_properties_type.clone(),
310        }
311    }
312}
313
314impl TypeUuidProvider for RigidBody {
315    fn type_uuid() -> Uuid {
316        uuid!("4be15a7c-3566-49c4-bba8-2f4ccc57ffed")
317    }
318}
319
320impl RigidBody {
321    /// Sets new linear velocity of the rigid body. Changing this parameter will wake up the rigid
322    /// body!
323    pub fn set_lin_vel(&mut self, lin_vel: Vector3<f32>) -> Vector3<f32> {
324        self.lin_vel.set_value_and_mark_modified(lin_vel)
325    }
326
327    /// Sets new linear velocity along the X axis of the rigid body. Changing this parameter will wake
328    /// up the rigid body!
329    pub fn set_lin_vel_x(&mut self, x_vel: f32) {
330        self.lin_vel.x = x_vel;
331    }
332
333    /// Sets new linear velocity along the Y axis of the rigid body. Changing this parameter will wake
334    /// up the rigid body!
335    pub fn set_lin_vel_y(&mut self, y_vel: f32) {
336        self.lin_vel.y = y_vel;
337    }
338
339    /// Sets new linear velocity along the Z axis of the rigid body. Changing this parameter will wake
340    /// up the rigid body!
341    pub fn set_lin_vel_z(&mut self, z_vel: f32) {
342        self.lin_vel.z = z_vel;
343    }
344
345    /// Returns current linear velocity of the rigid body.
346    pub fn lin_vel(&self) -> Vector3<f32> {
347        *self.lin_vel
348    }
349
350    /// Sets new angular velocity of the rigid body. Changing this parameter will wake up the rigid
351    /// body!
352    pub fn set_ang_vel(&mut self, ang_vel: Vector3<f32>) -> Vector3<f32> {
353        self.ang_vel.set_value_and_mark_modified(ang_vel)
354    }
355
356    /// Returns current angular velocity of the rigid body.
357    pub fn ang_vel(&self) -> Vector3<f32> {
358        *self.ang_vel
359    }
360
361    /// Sets _additional_ mass of the rigid body. It is called additional because real mass is defined
362    /// by colliders attached to the body and their density and volume.
363    pub fn set_mass(&mut self, mass: f32) -> f32 {
364        self.mass.set_value_and_mark_modified(mass)
365    }
366
367    /// Returns _additional_ mass of the rigid body.
368    pub fn mass(&self) -> f32 {
369        *self.mass
370    }
371
372    /// Sets angular damping of the rigid body. Angular damping will decrease angular velocity over
373    /// time. Default is zero.
374    pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
375        self.ang_damping.set_value_and_mark_modified(damping)
376    }
377
378    /// Returns current angular damping.
379    pub fn ang_damping(&self) -> f32 {
380        *self.ang_damping
381    }
382
383    /// Sets linear damping of the rigid body. Linear damping will decrease linear velocity over
384    /// time. Default is zero.
385    pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
386        self.lin_damping.set_value_and_mark_modified(damping)
387    }
388
389    /// Returns current linear damping.
390    pub fn lin_damping(&self) -> f32 {
391        *self.lin_damping
392    }
393
394    /// Locks rotations around X axis in world coordinates.
395    pub fn lock_x_rotations(&mut self, state: bool) -> bool {
396        self.x_rotation_locked.set_value_and_mark_modified(state)
397    }
398
399    /// Returns true if rotation around X axis is locked, false - otherwise.
400    pub fn is_x_rotation_locked(&self) -> bool {
401        *self.x_rotation_locked
402    }
403
404    /// Locks rotations around Y axis in world coordinates.
405    pub fn lock_y_rotations(&mut self, state: bool) -> bool {
406        self.y_rotation_locked.set_value_and_mark_modified(state)
407    }
408
409    /// Returns true if rotation around Y axis is locked, false - otherwise.
410    pub fn is_y_rotation_locked(&self) -> bool {
411        *self.y_rotation_locked
412    }
413
414    /// Locks rotations around Z axis in world coordinates.
415    pub fn lock_z_rotations(&mut self, state: bool) -> bool {
416        self.z_rotation_locked.set_value_and_mark_modified(state)
417    }
418
419    /// Returns true if rotation around Z axis is locked, false - otherwise.
420    pub fn is_z_rotation_locked(&self) -> bool {
421        *self.z_rotation_locked
422    }
423
424    /// Locks or unlocks rotations around all axes at once.
425    pub fn lock_rotations(&mut self, locked: bool) {
426        self.x_rotation_locked.set_value_and_mark_modified(locked);
427        self.y_rotation_locked.set_value_and_mark_modified(locked);
428        self.z_rotation_locked.set_value_and_mark_modified(locked);
429    }
430
431    /// Locks translation in world coordinates.
432    pub fn lock_translation(&mut self, state: bool) -> bool {
433        self.translation_locked.set_value_and_mark_modified(state)
434    }
435
436    /// Returns true if translation is locked, false - otherwise.
437    pub fn is_translation_locked(&self) -> bool {
438        *self.translation_locked
439    }
440
441    /// Sets new body type. See [`RigidBodyType`] for more info.
442    pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
443        self.body_type.set_value_and_mark_modified(body_type)
444    }
445
446    /// Returns current body type.
447    pub fn body_type(&self) -> RigidBodyType {
448        *self.body_type
449    }
450
451    /// Returns true if the rigid body is sleeping (temporarily excluded from simulation to save
452    /// resources), false - otherwise.
453    pub fn is_sleeping(&self) -> bool {
454        self.sleeping
455    }
456
457    /// Returns true if continuous collision detection is enabled, false - otherwise.
458    pub fn is_ccd_enabled(&self) -> bool {
459        *self.ccd_enabled
460    }
461
462    /// Enables or disables continuous collision detection. CCD is very useful for fast moving objects
463    /// to prevent accidental penetrations on high velocities.
464    pub fn enable_ccd(&mut self, enable: bool) -> bool {
465        self.ccd_enabled.set_value_and_mark_modified(enable)
466    }
467
468    /// Sets a gravity scale coefficient. Zero can be used to disable gravity.
469    pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
470        self.gravity_scale.set_value_and_mark_modified(scale)
471    }
472
473    /// Sets mass properties type.
474    pub fn set_mass_properties_type(
475        &mut self,
476        mass_properties_type: RigidBodyMassPropertiesType,
477    ) -> RigidBodyMassPropertiesType {
478        self.mass_properties_type
479            .set_value_and_mark_modified(mass_properties_type)
480    }
481
482    /// Returns current mass properties type.
483    pub fn mass_properties_type(&self) -> RigidBodyMassPropertiesType {
484        *self.mass_properties_type
485    }
486
487    /// Returns current gravity scale coefficient.
488    pub fn gravity_scale(&self) -> f32 {
489        *self.gravity_scale
490    }
491
492    /// Sets dominance group of the rigid body. A rigid body with higher dominance group will not
493    /// be affected by an object with lower dominance group (it will behave like it has an infinite
494    /// mass). This is very importance feature for character physics in games, you can set highest
495    /// dominance group to the player, and it won't be affected by any external forces.
496    pub fn set_dominance(&mut self, dominance: i8) -> i8 {
497        self.dominance.set_value_and_mark_modified(dominance)
498    }
499
500    /// Returns current dominance group.
501    pub fn dominance(&self) -> i8 {
502        *self.dominance
503    }
504
505    /// Applies a force at the center-of-mass of this rigid-body. The force will be applied in the
506    /// next simulation step. This does nothing on non-dynamic bodies.
507    pub fn apply_force(&mut self, force: Vector3<f32>) {
508        self.actions.get_mut().push_back(ApplyAction::Force(force))
509    }
510
511    /// Applies a torque at the center-of-mass of this rigid-body. The torque will be applied in
512    /// the next simulation step. This does nothing on non-dynamic bodies.
513    pub fn apply_torque(&mut self, torque: Vector3<f32>) {
514        self.actions
515            .get_mut()
516            .push_back(ApplyAction::Torque(torque))
517    }
518
519    /// Applies a force at the given world-space point of this rigid-body. The force will be applied
520    /// in the next simulation step. This does nothing on non-dynamic bodies.
521    pub fn apply_force_at_point(&mut self, force: Vector3<f32>, point: Vector3<f32>) {
522        self.actions
523            .get_mut()
524            .push_back(ApplyAction::ForceAtPoint { force, point })
525    }
526
527    /// Applies an impulse at the center-of-mass of this rigid-body. The impulse is applied right
528    /// away, changing the linear velocity. This does nothing on non-dynamic bodies.
529    pub fn apply_impulse(&mut self, impulse: Vector3<f32>) {
530        self.actions
531            .get_mut()
532            .push_back(ApplyAction::Impulse(impulse))
533    }
534
535    /// Applies an angular impulse at the center-of-mass of this rigid-body. The impulse is applied
536    /// right away, changing the angular velocity. This does nothing on non-dynamic bodies.
537    pub fn apply_torque_impulse(&mut self, torque_impulse: Vector3<f32>) {
538        self.actions
539            .get_mut()
540            .push_back(ApplyAction::TorqueImpulse(torque_impulse))
541    }
542
543    /// Applies an impulse at the given world-space point of this rigid-body. The impulse is applied
544    /// right away, changing the linear and/or angular velocities. This does nothing on non-dynamic
545    /// bodies.
546    pub fn apply_impulse_at_point(&mut self, impulse: Vector3<f32>, point: Vector3<f32>) {
547        self.actions
548            .get_mut()
549            .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
550    }
551
552    /// If this rigid body is kinematic, sets its future translation after
553    /// the next timestep integration.
554    pub fn set_next_kinematic_translation(&mut self, translation: Vector3<f32>) {
555        self.actions
556            .get_mut()
557            .push_back(ApplyAction::NextTranslation(translation));
558    }
559
560    /// If this rigid body is kinematic, sets its future orientation after
561    /// the next timestep integration.
562    pub fn set_next_kinematic_rotation(&mut self, rotation: UnitQuaternion<f32>) {
563        self.actions
564            .get_mut()
565            .push_back(ApplyAction::NextRotation(rotation));
566    }
567
568    /// If this rigid body is kinematic, sets its future position (translation and orientation) after
569    /// the next timestep integration.
570    pub fn set_next_kinematic_position(&mut self, position: Isometry3<f32>) {
571        self.actions
572            .get_mut()
573            .push_back(ApplyAction::NextPosition(position));
574    }
575
576    /// Sets whether the rigid body can sleep or not. If `false` is passed, it _automatically_ wake
577    /// up rigid body.
578    pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
579        self.can_sleep.set_value_and_mark_modified(can_sleep)
580    }
581
582    /// Returns true if the rigid body can sleep, false - otherwise.
583    pub fn is_can_sleep(&self) -> bool {
584        *self.can_sleep
585    }
586
587    /// Wakes up rigid body, forcing it to return to participate in the simulation.
588    pub fn wake_up(&mut self) {
589        self.actions.get_mut().push_back(ApplyAction::WakeUp)
590    }
591
592    pub(crate) fn need_sync_model(&self) -> bool {
593        self.lin_vel.need_sync()
594            || self.ang_vel.need_sync()
595            || self.lin_damping.need_sync()
596            || self.ang_damping.need_sync()
597            || self.body_type.need_sync()
598            || self.mass.need_sync()
599            || self.x_rotation_locked.need_sync()
600            || self.y_rotation_locked.need_sync()
601            || self.z_rotation_locked.need_sync()
602            || self.translation_locked.need_sync()
603            || self.ccd_enabled.need_sync()
604            || self.can_sleep.need_sync()
605            || self.dominance.need_sync()
606            || self.gravity_scale.need_sync()
607            || self.reset_forces.get()
608    }
609}
610
611impl ConstructorProvider<Node, Graph> for RigidBody {
612    fn constructor() -> NodeConstructor {
613        NodeConstructor::new::<Self>()
614            .with_variant("Rigid Body", |_| {
615                RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body"))
616                    .build_node()
617                    .into()
618            })
619            .with_group("Physics")
620    }
621}
622
623impl NodeTrait for RigidBody {
624    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
625        self.base.local_bounding_box()
626    }
627
628    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
629        self.base.world_bounding_box()
630    }
631
632    fn id(&self) -> Uuid {
633        Self::type_uuid()
634    }
635
636    fn on_removed_from_graph(&mut self, graph: &mut Graph) {
637        graph.physics.remove_body(self.native.get());
638        self.native.set(RigidBodyHandle::invalid());
639
640        Log::info(format!(
641            "Native rigid body was removed for node: {}",
642            self.name()
643        ));
644    }
645
646    fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
647        context.physics.sync_to_rigid_body_node(self_handle, self);
648    }
649
650    fn on_global_transform_changed(
651        &self,
652        new_global_transform: &Matrix4<f32>,
653        context: &mut SyncContext,
654    ) {
655        if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
656            context
657                .physics
658                .set_rigid_body_position(self, new_global_transform);
659        }
660    }
661
662    fn update(&mut self, context: &mut UpdateContext) {
663        context.physics.sync_rigid_body_node(
664            self,
665            // Rigid body can be root node of a scene, in this case it does not have a parent.
666            context
667                .nodes
668                .try_borrow(self.parent)
669                .ok()
670                .map(|p| p.global_transform())
671                .unwrap_or_else(Matrix4::identity),
672        );
673    }
674
675    fn validate(&self, scene: &Scene) -> Result<(), String> {
676        for &child in self.children() {
677            if let Ok(collider) = scene.graph.try_get_of_type::<Collider>(child) {
678                match collider.shape() {
679                    ColliderShape::Trimesh(_) | ColliderShape::Heightfield(_)
680                        if *self.body_type == RigidBodyType::Dynamic =>
681                    {
682                        return Err(
683                            "The 3D rigid body is marked as dynamic, but uses the collider \
684                        that cannot be dynamic. Consider making the rigid body static."
685                                .to_string(),
686                        )
687                    }
688                    _ => (),
689                }
690
691                return Ok(());
692            }
693        }
694
695        Err("The 3D rigid body must have at least one 3D collider as a \
696        direct child node to work correctly!"
697            .to_string())
698    }
699}
700
701/// Allows you to create rigid body in declarative manner.
702pub struct RigidBodyBuilder {
703    base_builder: BaseBuilder,
704    lin_vel: Vector3<f32>,
705    ang_vel: Vector3<f32>,
706    lin_damping: f32,
707    ang_damping: f32,
708    sleeping: bool,
709    body_type: RigidBodyType,
710    mass: f32,
711    x_rotation_locked: bool,
712    y_rotation_locked: bool,
713    z_rotation_locked: bool,
714    translation_locked: bool,
715    ccd_enabled: bool,
716    can_sleep: bool,
717    dominance: i8,
718    gravity_scale: f32,
719    mass_properties_type: RigidBodyMassPropertiesType,
720}
721
722impl RigidBodyBuilder {
723    /// Creates new rigid body builder.
724    pub fn new(base_builder: BaseBuilder) -> Self {
725        Self {
726            base_builder,
727            lin_vel: Default::default(),
728            ang_vel: Default::default(),
729            lin_damping: 0.0,
730            ang_damping: 0.0,
731            sleeping: false,
732            body_type: RigidBodyType::Dynamic,
733            mass: 1.0,
734            x_rotation_locked: false,
735            y_rotation_locked: false,
736            z_rotation_locked: false,
737            translation_locked: false,
738            ccd_enabled: false,
739            can_sleep: true,
740            dominance: 0,
741            gravity_scale: 1.0,
742            mass_properties_type: RigidBodyMassPropertiesType::Default,
743        }
744    }
745
746    /// Sets the desired body type.
747    pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
748        self.body_type = body_type;
749        self
750    }
751
752    /// Sets the desired _additional_ mass of the body.
753    pub fn with_mass(mut self, mass: f32) -> Self {
754        self.mass = mass;
755        self
756    }
757
758    /// Sets whether continuous collision detection should be enabled or not.
759    pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
760        self.ccd_enabled = enabled;
761        self
762    }
763
764    /// Sets desired linear velocity.
765    pub fn with_lin_vel(mut self, lin_vel: Vector3<f32>) -> Self {
766        self.lin_vel = lin_vel;
767        self
768    }
769
770    /// Sets desired angular velocity.
771    pub fn with_ang_vel(mut self, ang_vel: Vector3<f32>) -> Self {
772        self.ang_vel = ang_vel;
773        self
774    }
775
776    /// Sets desired angular damping.
777    pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
778        self.ang_damping = ang_damping;
779        self
780    }
781
782    /// Sets desired linear damping.
783    pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
784        self.lin_damping = lin_damping;
785        self
786    }
787
788    /// Sets whether the rotation around X axis of the body should be locked or not.
789    pub fn with_x_rotation_locked(mut self, x_rotation_locked: bool) -> Self {
790        self.x_rotation_locked = x_rotation_locked;
791        self
792    }
793
794    /// Sets whether the rotation around Y axis of the body should be locked or not.
795    pub fn with_y_rotation_locked(mut self, y_rotation_locked: bool) -> Self {
796        self.y_rotation_locked = y_rotation_locked;
797        self
798    }
799
800    /// Sets whether the rotation around Z axis of the body should be locked or not.
801    pub fn with_z_rotation_locked(mut self, z_rotation_locked: bool) -> Self {
802        self.z_rotation_locked = z_rotation_locked;
803        self
804    }
805
806    /// Sets whether the translation of the body should be locked or not.
807    pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
808        self.translation_locked = translation_locked;
809        self
810    }
811
812    /// Locks or unlocks rotations of the rigid body.
813    pub fn with_locked_rotations(mut self, locked: bool) -> Self {
814        self.x_rotation_locked = locked;
815        self.y_rotation_locked = locked;
816        self.z_rotation_locked = locked;
817        self
818    }
819
820    /// Sets initial state of the body (sleeping or not).
821    pub fn with_sleeping(mut self, sleeping: bool) -> Self {
822        self.sleeping = sleeping;
823        self
824    }
825
826    /// Sets whether rigid body can sleep or not.
827    pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
828        self.can_sleep = can_sleep;
829        self
830    }
831
832    /// Sets desired dominance group.
833    pub fn with_dominance(mut self, dominance: i8) -> Self {
834        self.dominance = dominance;
835        self
836    }
837
838    /// Sets desired gravity scale.
839    pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
840        self.gravity_scale = gravity_scale;
841        self
842    }
843
844    /// Sets mass properties type.
845    pub fn with_mass_properties_type(
846        mut self,
847        mass_properties_type: RigidBodyMassPropertiesType,
848    ) -> Self {
849        self.mass_properties_type = mass_properties_type;
850        self
851    }
852
853    /// Creates RigidBody node but does not add it to the graph.
854    pub fn build_rigid_body(self) -> RigidBody {
855        RigidBody {
856            base: self.base_builder.build_base(),
857            lin_vel: self.lin_vel.into(),
858            ang_vel: self.ang_vel.into(),
859            lin_damping: self.lin_damping.into(),
860            ang_damping: self.ang_damping.into(),
861            sleeping: self.sleeping,
862            body_type: self.body_type.into(),
863            mass: self.mass.into(),
864            x_rotation_locked: self.x_rotation_locked.into(),
865            y_rotation_locked: self.y_rotation_locked.into(),
866            z_rotation_locked: self.z_rotation_locked.into(),
867            translation_locked: self.translation_locked.into(),
868            ccd_enabled: self.ccd_enabled.into(),
869            can_sleep: self.can_sleep.into(),
870            dominance: self.dominance.into(),
871            gravity_scale: self.gravity_scale.into(),
872            native: Cell::new(RigidBodyHandle::invalid()),
873            actions: Default::default(),
874            reset_forces: Default::default(),
875            mass_properties_type: self.mass_properties_type.into(),
876        }
877    }
878
879    /// Creates RigidBody node but does not add it to the graph.
880    pub fn build_node(self) -> Node {
881        Node::new(self.build_rigid_body())
882    }
883
884    /// Creates RigidBody node and adds it to the graph.
885    pub fn build(self, graph: &mut Graph) -> Handle<RigidBody> {
886        graph.add_node(self.build_node()).to_variant()
887    }
888}