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::{BaseSceneGraph, 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    /// Returns current linear velocity of the rigid body.
234    pub fn lin_vel(&self) -> Vector2<f32> {
235        *self.lin_vel
236    }
237
238    /// Sets new angular velocity of the rigid body. Changing this parameter will wake up the rigid
239    /// body!
240    pub fn set_ang_vel(&mut self, ang_vel: f32) -> f32 {
241        self.ang_vel.set_value_and_mark_modified(ang_vel)
242    }
243
244    /// Returns current angular velocity of the rigid body.
245    pub fn ang_vel(&self) -> f32 {
246        *self.ang_vel
247    }
248
249    /// Sets _additional_ mass of the rigid body. It is called additional because real mass is defined
250    /// by colliders attached to the body and their density and volume.
251    pub fn set_mass(&mut self, mass: f32) -> f32 {
252        self.mass.set_value_and_mark_modified(mass)
253    }
254
255    /// Returns _additional_ mass of the rigid body.
256    pub fn mass(&self) -> f32 {
257        *self.mass
258    }
259
260    /// Sets angular damping of the rigid body. Angular damping will decrease angular velocity over
261    /// time. Default is zero.
262    pub fn set_ang_damping(&mut self, damping: f32) -> f32 {
263        self.ang_damping.set_value_and_mark_modified(damping)
264    }
265
266    /// Returns current angular damping.
267    pub fn ang_damping(&self) -> f32 {
268        *self.ang_damping
269    }
270
271    /// Sets linear damping of the rigid body. Linear damping will decrease linear velocity over
272    /// time. Default is zero.
273    pub fn set_lin_damping(&mut self, damping: f32) -> f32 {
274        self.lin_damping.set_value_and_mark_modified(damping)
275    }
276
277    /// Returns current linear damping.
278    pub fn lin_damping(&self) -> f32 {
279        *self.lin_damping
280    }
281
282    /// Locks rotations
283    pub fn lock_rotations(&mut self, state: bool) -> bool {
284        self.rotation_locked.set_value_and_mark_modified(state)
285    }
286
287    /// Returns true if rotation is locked, false - otherwise.
288    pub fn is_rotation_locked(&self) -> bool {
289        *self.rotation_locked
290    }
291
292    /// Locks translation in world coordinates.
293    pub fn lock_translation(&mut self, state: bool) -> bool {
294        self.translation_locked.set_value_and_mark_modified(state)
295    }
296
297    /// Returns true if translation is locked, false - otherwise.
298    pub fn is_translation_locked(&self) -> bool {
299        *self.translation_locked
300    }
301
302    /// Sets new body type. See [`RigidBodyType`] for more info.
303    pub fn set_body_type(&mut self, body_type: RigidBodyType) -> RigidBodyType {
304        self.body_type.set_value_and_mark_modified(body_type)
305    }
306
307    /// Returns current body type.
308    pub fn body_type(&self) -> RigidBodyType {
309        *self.body_type
310    }
311
312    /// Returns true if the rigid body is sleeping (temporarily excluded from simulation to save
313    /// resources), false - otherwise.
314    pub fn is_sleeping(&self) -> bool {
315        self.sleeping
316    }
317
318    /// Returns true if continuous collision detection is enabled, false - otherwise.
319    pub fn is_ccd_enabled(&self) -> bool {
320        *self.ccd_enabled
321    }
322
323    /// Enables or disables continuous collision detection. CCD is very useful for fast moving objects
324    /// to prevent accidental penetrations on high velocities.
325    pub fn enable_ccd(&mut self, enable: bool) -> bool {
326        self.ccd_enabled.set_value_and_mark_modified(enable)
327    }
328
329    /// Sets a gravity scale coefficient. Zero can be used to disable gravity.
330    pub fn set_gravity_scale(&mut self, scale: f32) -> f32 {
331        self.gravity_scale.set_value_and_mark_modified(scale)
332    }
333
334    /// Returns current gravity scale coefficient.
335    pub fn gravity_scale(&self) -> f32 {
336        *self.gravity_scale
337    }
338
339    /// Sets dominance group of the rigid body. A rigid body with higher dominance group will not
340    /// be affected by an object with lower dominance group (it will behave like it has an infinite
341    /// mass). This is very importance feature for character physics in games, you can set highest
342    /// dominance group to the player, and it won't be affected by any external forces.
343    pub fn set_dominance(&mut self, dominance: i8) -> i8 {
344        self.dominance.set_value_and_mark_modified(dominance)
345    }
346
347    /// Returns current dominance group.
348    pub fn dominance(&self) -> i8 {
349        *self.dominance
350    }
351
352    /// Applies a force at the center-of-mass of this rigid-body. The force will be applied in the
353    /// next simulation step. This does nothing on non-dynamic bodies.
354    pub fn apply_force(&mut self, force: Vector2<f32>) {
355        self.actions.get_mut().push_back(ApplyAction::Force(force))
356    }
357
358    /// Applies a torque at the center-of-mass of this rigid-body. The torque will be applied in
359    /// the next simulation step. This does nothing on non-dynamic bodies.
360    pub fn apply_torque(&mut self, torque: f32) {
361        self.actions
362            .get_mut()
363            .push_back(ApplyAction::Torque(torque))
364    }
365
366    /// Applies a force at the given world-space point of this rigid-body. The force will be applied
367    /// in the next simulation step. This does nothing on non-dynamic bodies.
368    pub fn apply_force_at_point(&mut self, force: Vector2<f32>, point: Vector2<f32>) {
369        self.actions
370            .get_mut()
371            .push_back(ApplyAction::ForceAtPoint { force, point })
372    }
373
374    /// Applies an impulse at the center-of-mass of this rigid-body. The impulse is applied right
375    /// away, changing the linear velocity. This does nothing on non-dynamic bodies.
376    pub fn apply_impulse(&mut self, impulse: Vector2<f32>) {
377        self.actions
378            .get_mut()
379            .push_back(ApplyAction::Impulse(impulse))
380    }
381
382    /// Applies an angular impulse at the center-of-mass of this rigid-body. The impulse is applied
383    /// right away, changing the angular velocity. This does nothing on non-dynamic bodies.
384    pub fn apply_torque_impulse(&mut self, torque_impulse: f32) {
385        self.actions
386            .get_mut()
387            .push_back(ApplyAction::TorqueImpulse(torque_impulse))
388    }
389
390    /// Applies an impulse at the given world-space point of this rigid-body. The impulse is applied
391    /// right away, changing the linear and/or angular velocities. This does nothing on non-dynamic
392    /// bodies.
393    pub fn apply_impulse_at_point(&mut self, impulse: Vector2<f32>, point: Vector2<f32>) {
394        self.actions
395            .get_mut()
396            .push_back(ApplyAction::ImpulseAtPoint { impulse, point })
397    }
398
399    /// If this rigid body is kinematic, sets its future translation after
400    /// the next timestep integration.
401    pub fn set_next_kinematic_translation(&mut self, translation: Vector2<f32>) {
402        self.actions
403            .get_mut()
404            .push_back(ApplyAction::NextTranslation(translation));
405    }
406
407    /// If this rigid body is kinematic, sets its future orientation after
408    /// the next timestep integration.
409    pub fn set_next_kinematic_rotation(&mut self, rotation: UnitComplex<f32>) {
410        self.actions
411            .get_mut()
412            .push_back(ApplyAction::NextRotation(rotation));
413    }
414
415    /// If this rigid body is kinematic, sets its future position (translation and orientation) after
416    /// the next timestep integration.
417    pub fn set_next_kinematic_position(&mut self, position: Isometry2<f32>) {
418        self.actions
419            .get_mut()
420            .push_back(ApplyAction::NextPosition(position));
421    }
422
423    /// Sets whether the rigid body can sleep or not. If `false` is passed, it _automatically_ wake
424    /// up rigid body.
425    pub fn set_can_sleep(&mut self, can_sleep: bool) -> bool {
426        self.can_sleep.set_value_and_mark_modified(can_sleep)
427    }
428
429    /// Returns true if the rigid body can sleep, false - otherwise.
430    pub fn is_can_sleep(&self) -> bool {
431        *self.can_sleep
432    }
433
434    /// Wakes up rigid body, forcing it to return to participate in the simulation.
435    pub fn wake_up(&mut self) {
436        self.actions.get_mut().push_back(ApplyAction::WakeUp)
437    }
438
439    pub(crate) fn need_sync_model(&self) -> bool {
440        self.lin_vel.need_sync()
441            || self.ang_vel.need_sync()
442            || self.lin_damping.need_sync()
443            || self.ang_damping.need_sync()
444            || self.body_type.need_sync()
445            || self.mass.need_sync()
446            || self.rotation_locked.need_sync()
447            || self.translation_locked.need_sync()
448            || self.ccd_enabled.need_sync()
449            || self.can_sleep.need_sync()
450            || self.dominance.need_sync()
451            || self.gravity_scale.need_sync()
452            || self.reset_forces.get()
453    }
454}
455
456impl ConstructorProvider<Node, Graph> for RigidBody {
457    fn constructor() -> NodeConstructor {
458        NodeConstructor::new::<Self>()
459            .with_variant("Rigid Body", |_| {
460                RigidBodyBuilder::new(BaseBuilder::new().with_name("Rigid Body 2D"))
461                    .build_node()
462                    .into()
463            })
464            .with_group("Physics 2D")
465    }
466}
467
468impl NodeTrait for RigidBody {
469    fn local_bounding_box(&self) -> AxisAlignedBoundingBox {
470        self.base.local_bounding_box()
471    }
472
473    fn world_bounding_box(&self) -> AxisAlignedBoundingBox {
474        self.base.world_bounding_box()
475    }
476
477    fn id(&self) -> Uuid {
478        Self::type_uuid()
479    }
480
481    fn on_removed_from_graph(&mut self, graph: &mut Graph) {
482        graph.physics2d.remove_body(self.native.get());
483        self.native.set(RigidBodyHandle::invalid());
484
485        Log::info(format!(
486            "Native rigid body was removed for node: {}",
487            self.name()
488        ));
489    }
490
491    fn sync_native(&self, self_handle: Handle<Node>, context: &mut SyncContext) {
492        context.physics2d.sync_to_rigid_body_node(self_handle, self);
493    }
494
495    fn on_global_transform_changed(
496        &self,
497        new_global_transform: &Matrix4<f32>,
498        context: &mut SyncContext,
499    ) {
500        if !m4x4_approx_eq(new_global_transform, &self.global_transform()) {
501            context
502                .physics2d
503                .set_rigid_body_position(self, new_global_transform);
504        }
505    }
506
507    fn update(&mut self, context: &mut UpdateContext) {
508        context.physics2d.sync_rigid_body_node(
509            self,
510            // Rigid body 2D can be root node of a scene, in this case it does not have a parent.
511            context
512                .nodes
513                .try_borrow(self.parent)
514                .map(|p| p.global_transform())
515                .unwrap_or_else(Matrix4::identity),
516        );
517    }
518
519    fn validate(&self, scene: &Scene) -> Result<(), String> {
520        for &child in self.children() {
521            if scene.graph.try_get_of_type::<Collider>(child).is_some() {
522                return Ok(());
523            }
524        }
525
526        Err("The 2D rigid body must have at least one 2D collider as a \
527        direct child node to work correctly!"
528            .to_string())
529    }
530}
531
532/// Allows you to create rigid body in declarative manner.
533pub struct RigidBodyBuilder {
534    base_builder: BaseBuilder,
535    lin_vel: Vector2<f32>,
536    ang_vel: f32,
537    lin_damping: f32,
538    ang_damping: f32,
539    sleeping: bool,
540    body_type: RigidBodyType,
541    mass: f32,
542    rotation_locked: bool,
543    translation_locked: bool,
544    ccd_enabled: bool,
545    can_sleep: bool,
546    dominance: i8,
547    gravity_scale: f32,
548}
549
550impl RigidBodyBuilder {
551    /// Creates new rigid body builder.
552    pub fn new(base_builder: BaseBuilder) -> Self {
553        Self {
554            base_builder,
555            lin_vel: Default::default(),
556            ang_vel: Default::default(),
557            lin_damping: 0.0,
558            ang_damping: 0.0,
559            sleeping: false,
560            body_type: RigidBodyType::Dynamic,
561            mass: 1.0,
562            rotation_locked: false,
563            translation_locked: false,
564            ccd_enabled: false,
565            can_sleep: true,
566            dominance: 0,
567            gravity_scale: 1.0,
568        }
569    }
570
571    /// Sets the desired body type.
572    pub fn with_body_type(mut self, body_type: RigidBodyType) -> Self {
573        self.body_type = body_type;
574        self
575    }
576
577    /// Sets the desired _additional_ mass of the body.
578    pub fn with_mass(mut self, mass: f32) -> Self {
579        self.mass = mass;
580        self
581    }
582
583    /// Sets whether continuous collision detection should be enabled or not.
584    pub fn with_ccd_enabled(mut self, enabled: bool) -> Self {
585        self.ccd_enabled = enabled;
586        self
587    }
588
589    /// Sets desired linear velocity.
590    pub fn with_lin_vel(mut self, lin_vel: Vector2<f32>) -> Self {
591        self.lin_vel = lin_vel;
592        self
593    }
594
595    /// Sets desired angular velocity.
596    pub fn with_ang_vel(mut self, ang_vel: f32) -> Self {
597        self.ang_vel = ang_vel;
598        self
599    }
600
601    /// Sets desired angular damping.
602    pub fn with_ang_damping(mut self, ang_damping: f32) -> Self {
603        self.ang_damping = ang_damping;
604        self
605    }
606
607    /// Sets desired linear damping.
608    pub fn with_lin_damping(mut self, lin_damping: f32) -> Self {
609        self.lin_damping = lin_damping;
610        self
611    }
612
613    /// Sets whether the rotation around X axis of the body should be locked or not.
614    pub fn with_rotation_locked(mut self, rotation_locked: bool) -> Self {
615        self.rotation_locked = rotation_locked;
616        self
617    }
618
619    /// Sets whether the translation of the body should be locked or not.
620    pub fn with_translation_locked(mut self, translation_locked: bool) -> Self {
621        self.translation_locked = translation_locked;
622        self
623    }
624
625    /// Sets desired dominance group.
626    pub fn with_dominance(mut self, dominance: i8) -> Self {
627        self.dominance = dominance;
628        self
629    }
630
631    /// Sets desired gravity scale.
632    pub fn with_gravity_scale(mut self, gravity_scale: f32) -> Self {
633        self.gravity_scale = gravity_scale;
634        self
635    }
636
637    /// Sets initial state of the body (sleeping or not).
638    pub fn with_sleeping(mut self, sleeping: bool) -> Self {
639        self.sleeping = sleeping;
640        self
641    }
642
643    /// Sets whether rigid body can sleep or not.
644    pub fn with_can_sleep(mut self, can_sleep: bool) -> Self {
645        self.can_sleep = can_sleep;
646        self
647    }
648
649    /// Creates RigidBody node but does not add it to the graph.
650    pub fn build_rigid_body(self) -> RigidBody {
651        RigidBody {
652            base: self.base_builder.build_base(),
653            lin_vel: self.lin_vel.into(),
654            ang_vel: self.ang_vel.into(),
655            lin_damping: self.lin_damping.into(),
656            ang_damping: self.ang_damping.into(),
657            sleeping: self.sleeping,
658            body_type: self.body_type.into(),
659            mass: self.mass.into(),
660            rotation_locked: self.rotation_locked.into(),
661            translation_locked: self.translation_locked.into(),
662            ccd_enabled: self.ccd_enabled.into(),
663            can_sleep: self.can_sleep.into(),
664            dominance: self.dominance.into(),
665            gravity_scale: self.gravity_scale.into(),
666            native: Cell::new(RigidBodyHandle::invalid()),
667            actions: Default::default(),
668            reset_forces: Default::default(),
669        }
670    }
671
672    /// Creates RigidBody node but does not add it to the graph.
673    pub fn build_node(self) -> Node {
674        Node::new(self.build_rigid_body())
675    }
676
677    /// Creates RigidBody node and adds it to the graph.
678    pub fn build(self, graph: &mut Graph) -> Handle<Node> {
679        graph.add_node(self.build_node())
680    }
681}