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::{Matrix4, Vector3},
35        log::Log,
36        math::{aabb::AxisAlignedBoundingBox, m4x4_approx_eq},
37        parking_lot::Mutex,
38        pool::Handle,
39        reflect::prelude::*,
40        type_traits::prelude::*,
41        uuid::{uuid, Uuid},
42        variable::InheritableVariable,
43        visitor::prelude::*,
44    },
45    scene::{
46        base::{Base, BaseBuilder},
47        collider::Collider,
48        graph::Graph,
49        node::{Node, NodeTrait, SyncContext, UpdateContext},
50        Scene,
51    },
52};
53use fyrox_core::uuid_provider;
54use fyrox_graph::constructor::ConstructorProvider;
55use fyrox_graph::{BaseSceneGraph, SceneGraph};
56use rapier3d::{dynamics, prelude::RigidBodyHandle};
57use std::{
58    cell::Cell,
59    collections::VecDeque,
60    fmt::{Debug, Formatter},
61    ops::{Deref, DerefMut},
62};
63use strum_macros::{AsRefStr, EnumString, VariantNames};
64
65/// 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}
148
149/// Rigid body is a physics entity that responsible for the dynamics and kinematics of the solid.
150/// Use this node when you need to simulate real-world physics in your game.
151///
152/// # Sleeping
153///
154/// Rigid body that does not move for some time will go asleep. This means that the body will not
155/// move unless it is woken up by some other moving body. This feature allows to save CPU resources.
156#[derive(Visit, Reflect, ComponentProvider)]
157pub struct RigidBody {
158    base: Base,
159
160    #[reflect(setter = "set_lin_vel")]
161    pub(crate) lin_vel: InheritableVariable<Vector3<f32>>,
162
163    #[reflect(setter = "set_ang_vel")]
164    pub(crate) ang_vel: InheritableVariable<Vector3<f32>>,
165
166    #[reflect(setter = "set_lin_damping")]
167    pub(crate) lin_damping: InheritableVariable<f32>,
168
169    #[reflect(setter = "set_ang_damping")]
170    pub(crate) ang_damping: InheritableVariable<f32>,
171
172    #[reflect(setter = "set_body_type")]
173    pub(crate) body_type: InheritableVariable<RigidBodyType>,
174
175    #[reflect(min_value = 0.0, step = 0.05)]
176    #[reflect(setter = "set_mass")]
177    pub(crate) mass: InheritableVariable<f32>,
178
179    #[reflect(setter = "lock_x_rotations")]
180    pub(crate) x_rotation_locked: InheritableVariable<bool>,
181
182    #[reflect(setter = "lock_y_rotations")]
183    pub(crate) y_rotation_locked: InheritableVariable<bool>,
184
185    #[reflect(setter = "lock_z_rotations")]
186    pub(crate) z_rotation_locked: InheritableVariable<bool>,
187
188    #[reflect(setter = "lock_translation")]
189    pub(crate) translation_locked: InheritableVariable<bool>,
190
191    #[reflect(setter = "enable_ccd")]
192    pub(crate) ccd_enabled: InheritableVariable<bool>,
193
194    #[reflect(setter = "set_can_sleep")]
195    pub(crate) can_sleep: InheritableVariable<bool>,
196
197    #[reflect(setter = "set_dominance")]
198    pub(crate) dominance: InheritableVariable<i8>,
199
200    #[reflect(setter = "set_gravity_scale")]
201    pub(crate) gravity_scale: InheritableVariable<f32>,
202
203    #[visit(skip)]
204    #[reflect(hidden)]
205    pub(crate) sleeping: bool,
206    #[visit(skip)]
207    #[reflect(hidden)]
208    pub(crate) reset_forces: Cell<bool>,
209    #[visit(skip)]
210    #[reflect(hidden)]
211    pub(crate) native: Cell<RigidBodyHandle>,
212    #[visit(skip)]
213    #[reflect(hidden)]
214    pub(crate) actions: Mutex<VecDeque<ApplyAction>>,
215}
216
217impl Debug for RigidBody {
218    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
219        write!(f, "RigidBody")
220    }
221}
222
223impl Default for RigidBody {
224    fn default() -> Self {
225        Self {
226            base: Default::default(),
227            lin_vel: Default::default(),
228            ang_vel: Default::default(),
229            lin_damping: Default::default(),
230            ang_damping: Default::default(),
231            sleeping: Default::default(),
232            body_type: InheritableVariable::new_modified(RigidBodyType::Dynamic),
233            mass: InheritableVariable::new_modified(1.0),
234            x_rotation_locked: Default::default(),
235            y_rotation_locked: Default::default(),
236            z_rotation_locked: Default::default(),
237            translation_locked: Default::default(),
238            ccd_enabled: Default::default(),
239            can_sleep: InheritableVariable::new_modified(true),
240            dominance: Default::default(),
241            gravity_scale: InheritableVariable::new_modified(1.0),
242            native: Cell::new(RigidBodyHandle::invalid()),
243            actions: Default::default(),
244            reset_forces: Default::default(),
245        }
246    }
247}
248
249impl Deref for RigidBody {
250    type Target = Base;
251
252    fn deref(&self) -> &Self::Target {
253        &self.base
254    }
255}
256
257impl DerefMut for RigidBody {
258    fn deref_mut(&mut self) -> &mut Self::Target {
259        &mut self.base
260    }
261}
262
263impl Clone for RigidBody {
264    fn clone(&self) -> Self {
265        Self {
266            base: self.base.clone(),
267            lin_vel: self.lin_vel.clone(),
268            ang_vel: self.ang_vel.clone(),
269            lin_damping: self.lin_damping.clone(),
270            ang_damping: self.ang_damping.clone(),
271            sleeping: self.sleeping,
272            body_type: self.body_type.clone(),
273            mass: self.mass.clone(),
274            x_rotation_locked: self.x_rotation_locked.clone(),
275            y_rotation_locked: self.y_rotation_locked.clone(),
276            z_rotation_locked: self.z_rotation_locked.clone(),
277            translation_locked: self.translation_locked.clone(),
278            ccd_enabled: self.ccd_enabled.clone(),
279            can_sleep: self.can_sleep.clone(),
280            dominance: self.dominance.clone(),
281            gravity_scale: self.gravity_scale.clone(),
282            // Do not copy. The copy will have its own native representation.
283            native: Cell::new(RigidBodyHandle::invalid()),
284            actions: Default::default(),
285            reset_forces: self.reset_forces.clone(),
286        }
287    }
288}
289
290impl TypeUuidProvider for RigidBody {
291    fn type_uuid() -> Uuid {
292        uuid!("4be15a7c-3566-49c4-bba8-2f4ccc57ffed")
293    }
294}
295
296impl RigidBody {
297    /// Sets new linear velocity of the rigid body. Changing this parameter will wake up the rigid
298    /// body!
299    pub fn set_lin_vel(&mut self, lin_vel: Vector3<f32>) -> Vector3<f32> {
300        self.lin_vel.set_value_and_mark_modified(lin_vel)
301    }
302
303    /// Returns current linear velocity of the rigid body.
304    pub fn lin_vel(&self) -> Vector3<f32> {
305        *self.lin_vel
306    }
307
308    /// Sets new angular velocity of the rigid body. Changing this parameter will wake up the rigid
309    /// body!
310    pub fn set_ang_vel(&mut self, ang_vel: Vector3<f32>) -> Vector3<f32> {
311        self.ang_vel.set_value_and_mark_modified(ang_vel)
312    }
313
314    /// Returns current angular velocity of the rigid body.
315    pub fn ang_vel(&self) -> Vector3<f32> {
316        *self.ang_vel
317    }
318
319    /// Sets _additional_ mass of the rigid body. It is called additional because real mass is defined
320    /// by colliders attached to the body and their density and volume.
321    pub fn set_mass(&mut self, mass: f32) -> f32 {
322        self.mass.set_value_and_mark_modified(mass)
323    }
324
325    /// Returns _additional_ mass of the rigid body.
326    pub fn mass(&self) -> f32 {
327        *self.mass
328    }
329
330    /// Sets angular damping of the rigid body. Angular damping will decrease angular velocity over
331    /// time. Default is zero.
332    pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
333        self.ang_damping.set_value_and_mark_modified(damping)
334    }
335
336    /// Returns current angular damping.
337    pub fn ang_damping(&self) -> f32 {
338        *self.ang_damping
339    }
340
341    /// Sets linear damping of the rigid body. Linear damping will decrease linear velocity over
342    /// time. Default is zero.
343    pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
344        self.lin_damping.set_value_and_mark_modified(damping)
345    }
346
347    /// Returns current linear damping.
348    pub fn lin_damping(&self) -> f32 {
349        *self.lin_damping
350    }
351
352    /// Locks rotations around X axis in world coordinates.
353    pub fn lock_x_rotations(&mut self, state: bool) -> bool {
354        self.x_rotation_locked.set_value_and_mark_modified(state)
355    }
356
357    /// Returns true if rotation around X axis is locked, false - otherwise.
358    pub fn is_x_rotation_locked(&self) -> bool {
359        *self.x_rotation_locked
360    }
361
362    /// Locks rotations around Y axis in world coordinates.
363    pub fn lock_y_rotations(&mut self, state: bool) -> bool {
364        self.y_rotation_locked.set_value_and_mark_modified(state)
365    }
366
367    /// Returns true if rotation around Y axis is locked, false - otherwise.    
368    pub fn is_y_rotation_locked(&self) -> bool {
369        *self.y_rotation_locked
370    }
371
372    /// Locks rotations around Z axis in world coordinates.
373    pub fn lock_z_rotations(&mut self, state: bool) -> bool {
374        self.z_rotation_locked.set_value_and_mark_modified(state)
375    }
376
377    /// Returns true if rotation around Z axis is locked, false - otherwise.    
378    pub fn is_z_rotation_locked(&self) -> bool {
379        *self.z_rotation_locked
380    }
381
382    /// Locks or unlocks rotations around all axes at once.
383    pub fn lock_rotations(&mut self, locked: bool) {
384        self.x_rotation_locked.set_value_and_mark_modified(locked);
385        self.y_rotation_locked.set_value_and_mark_modified(locked);
386        self.z_rotation_locked.set_value_and_mark_modified(locked);
387    }
388
389    /// Locks translation in world coordinates.
390    pub fn lock_translation(&mut self, state: bool) -> bool {
391        self.translation_locked.set_value_and_mark_modified(state)
392    }
393
394    /// Returns true if translation is locked, false - otherwise.    
395    pub fn is_translation_locked(&self) -> bool {
396        *self.translation_locked
397    }
398
399    /// Sets new body type. See [`RigidBodyType`] for more info.
400    pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
401        self.body_type.set_value_and_mark_modified(body_type)
402    }
403
404    /// Returns current body type.
405    pub fn body_type(&self) -> RigidBodyType {
406        *self.body_type
407    }
408
409    /// Returns true if the rigid body is sleeping (temporarily excluded from simulation to save
410    /// resources), false - otherwise.
411    pub fn is_sleeping(&self) -> bool {
412        self.sleeping
413    }
414
415    /// Returns true if continuous collision detection is enabled, false - otherwise.
416    pub fn is_ccd_enabled(&self) -> bool {
417        *self.ccd_enabled
418    }
419
420    /// Enables or disables continuous collision detection. CCD is very useful for fast moving objects
421    /// to prevent accidental penetrations on high velocities.
422    pub fn enable_ccd(&mut self, enable: bool) -> bool {
423        self.ccd_enabled.set_value_and_mark_modified(enable)
424    }
425
426    /// Sets a gravity scale coefficient. Zero can be used to disable gravity.
427    pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
428        self.gravity_scale.set_value_and_mark_modified(scale)
429    }
430
431    /// Returns current gravity scale coefficient.
432    pub fn gravity_scale(&self) -> f32 {
433        *self.gravity_scale
434    }
435
436    /// Sets dominance group of the rigid body. A rigid body with higher dominance group will not
437    /// be affected by an object with lower dominance group (it will behave like it has an infinite
438    /// mass). This is very importance feature for character physics in games, you can set highest
439    /// dominance group to the player, and it won't be affected by any external forces.
440    pub fn set_dominance(&mut self, dominance: i8) -> i8 {
441        self.dominance.set_value_and_mark_modified(dominance)
442    }
443
444    /// Returns current dominance group.
445    pub fn dominance(&self) -> i8 {
446        *self.dominance
447    }
448
449    /// Applies a force at the center-of-mass of this rigid-body. The force will be applied in the
450    /// next simulation step. This does nothing on non-dynamic bodies.
451    pub fn apply_force(&mut self, force: Vector3<f32>) {
452        self.actions.get_mut().push_back(ApplyAction::Force(force))
453    }
454
455    /// Applies a torque at the center-of-mass of this rigid-body. The torque will be applied in
456    /// the next simulation step. This does nothing on non-dynamic bodies.
457    pub fn apply_torque(&mut self, torque: Vector3<f32>) {
458        self.actions
459            .get_mut()
460            .push_back(ApplyAction::Torque(torque))
461    }
462
463    /// Applies a force at the given world-space point of this rigid-body. The force will be applied
464    /// in the next simulation step. This does nothing on non-dynamic bodies.
465    pub fn apply_force_at_point(&mut self, force: Vector3<f32>, point: Vector3<f32>) {
466        self.actions
467            .get_mut()
468            .push_back(ApplyAction::ForceAtPoint { force, point })
469    }
470
471    /// Applies an impulse at the center-of-mass of this rigid-body. The impulse is applied right
472    /// away, changing the linear velocity. This does nothing on non-dynamic bodies.
473    pub fn apply_impulse(&mut self, impulse: Vector3<f32>) {
474        self.actions
475            .get_mut()
476            .push_back(ApplyAction::Impulse(impulse))
477    }
478
479    /// Applies an angular impulse at the center-of-mass of this rigid-body. The impulse is applied
480    /// right away, changing the angular velocity. This does nothing on non-dynamic bodies.
481    pub fn apply_torque_impulse(&mut self, torque_impulse: Vector3<f32>) {
482        self.actions
483            .get_mut()
484            .push_back(ApplyAction::TorqueImpulse(torque_impulse))
485    }
486
487    /// Applies an impulse at the given world-space point of this rigid-body. The impulse is applied
488    /// right away, changing the linear and/or angular velocities. This does nothing on non-dynamic
489    /// bodies.
490    pub fn apply_impulse_at_point(&mut self, impulse: Vector3<f32>, point: Vector3<f32>) {
491        self.actions
492            .get_mut()
493            .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
494    }
495
496    /// Sets whether the rigid body can sleep or not. If `false` is passed, it _automatically_ wake
497    /// up rigid body.
498    pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
499        self.can_sleep.set_value_and_mark_modified(can_sleep)
500    }
501
502    /// Returns true if the rigid body can sleep, false - otherwise.
503    pub fn is_can_sleep(&self) -> bool {
504        *self.can_sleep
505    }
506
507    /// Wakes up rigid body, forcing it to return to participate in the simulation.
508    pub fn wake_up(&mut self) {
509        self.actions.get_mut().push_back(ApplyAction::WakeUp)
510    }
511
512    pub(crate) fn need_sync_model(&self) -> bool {
513        self.lin_vel.need_sync()
514            || self.ang_vel.need_sync()
515            || self.lin_damping.need_sync()
516            || self.ang_damping.need_sync()
517            || self.body_type.need_sync()
518            || self.mass.need_sync()
519            || self.x_rotation_locked.need_sync()
520            || self.y_rotation_locked.need_sync()
521            || self.z_rotation_locked.need_sync()
522            || self.translation_locked.need_sync()
523            || self.ccd_enabled.need_sync()
524            || self.can_sleep.need_sync()
525            || self.dominance.need_sync()
526            || self.gravity_scale.need_sync()
527            || self.reset_forces.get()
528    }
529}
530
531impl ConstructorProvider<Node, Graph> for RigidBody {
532    fn constructor() -> NodeConstructor {
533        NodeConstructor::new::<Self>()
534            .with_variant("Rigid Body", |_| {
535                RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body"))
536                    .build_node()
537                    .into()
538            })
539            .with_group("Physics")
540    }
541}
542
543impl NodeTrait for RigidBody {
544    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
545        self.base.local_bounding_box()
546    }
547
548    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
549        self.base.world_bounding_box()
550    }
551
552    fn id(&self) -> Uuid {
553        Self::type_uuid()
554    }
555
556    fn on_removed_from_graph(&mut self, graph: &mut Graph) {
557        graph.physics.remove_body(self.native.get());
558        self.native.set(RigidBodyHandle::invalid());
559
560        Log::info(format!(
561            "Native rigid body was removed for node: {}",
562            self.name()
563        ));
564    }
565
566    fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
567        context.physics.sync_to_rigid_body_node(self_handle, self);
568    }
569
570    fn on_global_transform_changed(
571        &self,
572        new_global_transform: &Matrix4<f32>,
573        context: &mut SyncContext,
574    ) {
575        if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
576            context
577                .physics
578                .set_rigid_body_position(self, new_global_transform);
579        }
580    }
581
582    fn update(&mut self, context: &mut UpdateContext) {
583        context.physics.sync_rigid_body_node(
584            self,
585            // Rigid body can be root node of a scene, in this case it does not have a parent.
586            context
587                .nodes
588                .try_borrow(self.parent)
589                .map(|p| p.global_transform())
590                .unwrap_or_else(Matrix4::identity),
591        );
592    }
593
594    fn validate(&self, scene: &Scene) -> Result<(), String> {
595        for &child in self.children() {
596            if scene.graph.try_get_of_type::<Collider>(child).is_some() {
597                return Ok(());
598            }
599        }
600
601        Err("The 3D rigid body must have at least one 3D collider as a \
602        direct child node to work correctly!"
603            .to_string())
604    }
605}
606
607/// Allows you to create rigid body in declarative manner.
608pub struct RigidBodyBuilder {
609    base_builder: BaseBuilder,
610    lin_vel: Vector3<f32>,
611    ang_vel: Vector3<f32>,
612    lin_damping: f32,
613    ang_damping: f32,
614    sleeping: bool,
615    body_type: RigidBodyType,
616    mass: f32,
617    x_rotation_locked: bool,
618    y_rotation_locked: bool,
619    z_rotation_locked: bool,
620    translation_locked: bool,
621    ccd_enabled: bool,
622    can_sleep: bool,
623    dominance: i8,
624    gravity_scale: f32,
625}
626
627impl RigidBodyBuilder {
628    /// Creates new rigid body builder.
629    pub fn new(base_builder: BaseBuilder) -> Self {
630        Self {
631            base_builder,
632            lin_vel: Default::default(),
633            ang_vel: Default::default(),
634            lin_damping: 0.0,
635            ang_damping: 0.0,
636            sleeping: false,
637            body_type: RigidBodyType::Dynamic,
638            mass: 1.0,
639            x_rotation_locked: false,
640            y_rotation_locked: false,
641            z_rotation_locked: false,
642            translation_locked: false,
643            ccd_enabled: false,
644            can_sleep: true,
645            dominance: 0,
646            gravity_scale: 1.0,
647        }
648    }
649
650    /// Sets the desired body type.
651    pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
652        self.body_type = body_type;
653        self
654    }
655
656    /// Sets the desired _additional_ mass of the body.
657    pub fn with_mass(mut self, mass: f32) -> Self {
658        self.mass = mass;
659        self
660    }
661
662    /// Sets whether continuous collision detection should be enabled or not.
663    pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
664        self.ccd_enabled = enabled;
665        self
666    }
667
668    /// Sets desired linear velocity.
669    pub fn with_lin_vel(mut self, lin_vel: Vector3<f32>) -> Self {
670        self.lin_vel = lin_vel;
671        self
672    }
673
674    /// Sets desired angular velocity.
675    pub fn with_ang_vel(mut self, ang_vel: Vector3<f32>) -> Self {
676        self.ang_vel = ang_vel;
677        self
678    }
679
680    /// Sets desired angular damping.
681    pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
682        self.ang_damping = ang_damping;
683        self
684    }
685
686    /// Sets desired linear damping.
687    pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
688        self.lin_damping = lin_damping;
689        self
690    }
691
692    /// Sets whether the rotation around X axis of the body should be locked or not.
693    pub fn with_x_rotation_locked(mut self, x_rotation_locked: bool) -> Self {
694        self.x_rotation_locked = x_rotation_locked;
695        self
696    }
697
698    /// Sets whether the rotation around Y axis of the body should be locked or not.
699    pub fn with_y_rotation_locked(mut self, y_rotation_locked: bool) -> Self {
700        self.y_rotation_locked = y_rotation_locked;
701        self
702    }
703
704    /// Sets whether the rotation around Z axis of the body should be locked or not.
705    pub fn with_z_rotation_locked(mut self, z_rotation_locked: bool) -> Self {
706        self.z_rotation_locked = z_rotation_locked;
707        self
708    }
709
710    /// Sets whether the translation of the body should be locked or not.
711    pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
712        self.translation_locked = translation_locked;
713        self
714    }
715
716    /// Locks or unlocks rotations of the rigid body.
717    pub fn with_locked_rotations(mut self, locked: bool) -> Self {
718        self.x_rotation_locked = locked;
719        self.y_rotation_locked = locked;
720        self.z_rotation_locked = locked;
721        self
722    }
723
724    /// Sets initial state of the body (sleeping or not).
725    pub fn with_sleeping(mut self, sleeping: bool) -> Self {
726        self.sleeping = sleeping;
727        self
728    }
729
730    /// Sets whether rigid body can sleep or not.
731    pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
732        self.can_sleep = can_sleep;
733        self
734    }
735
736    /// Sets desired dominance group.
737    pub fn with_dominance(mut self, dominance: i8) -> Self {
738        self.dominance = dominance;
739        self
740    }
741
742    /// Sets desired gravity scale.
743    pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
744        self.gravity_scale = gravity_scale;
745        self
746    }
747
748    /// Creates RigidBody node but does not add it to the graph.
749    pub fn build_rigid_body(self) -> RigidBody {
750        RigidBody {
751            base: self.base_builder.build_base(),
752            lin_vel: self.lin_vel.into(),
753            ang_vel: self.ang_vel.into(),
754            lin_damping: self.lin_damping.into(),
755            ang_damping: self.ang_damping.into(),
756            sleeping: self.sleeping,
757            body_type: self.body_type.into(),
758            mass: self.mass.into(),
759            x_rotation_locked: self.x_rotation_locked.into(),
760            y_rotation_locked: self.y_rotation_locked.into(),
761            z_rotation_locked: self.z_rotation_locked.into(),
762            translation_locked: self.translation_locked.into(),
763            ccd_enabled: self.ccd_enabled.into(),
764            can_sleep: self.can_sleep.into(),
765            dominance: self.dominance.into(),
766            gravity_scale: self.gravity_scale.into(),
767            native: Cell::new(RigidBodyHandle::invalid()),
768            actions: Default::default(),
769            reset_forces: Default::default(),
770        }
771    }
772
773    /// Creates RigidBody node but does not add it to the graph.
774    pub fn build_node(self) -> Node {
775        Node::new(self.build_rigid_body())
776    }
777
778    /// Creates RigidBody node and adds it to the graph.
779    pub fn build(self, graph: &mut Graph) -> Handle<Node> {
780        graph.add_node(self.build_node())
781    }
782}