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