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