Skip to main content

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