Skip to main content

bevy_rapier3d/dynamics/
rigid_body.rs

1use crate::math::Vect;
2use bevy::prelude::*;
3use rapier::prelude::{
4    LockedAxes as RapierLockedAxes, Pose, RigidBodyActivation, RigidBodyHandle, RigidBodyType,
5};
6use std::ops::{Add, AddAssign, Sub, SubAssign};
7
8#[cfg(doc)]
9use rapier::dynamics::IntegrationParameters;
10
11/// The Rapier handle of a [`RigidBody`] that was inserted to the physics scene.
12#[derive(Copy, Clone, Debug, Component)]
13pub struct RapierRigidBodyHandle(pub RigidBodyHandle);
14
15/// A [`RigidBody`].
16///
17/// Related components:
18/// - [`GlobalTransform`]: used as the ground truth for the bodies position.
19/// - [`Velocity`]
20/// - [`ExternalImpulse`]
21/// - [`ExternalForce`]
22/// - [`AdditionalMassProperties`]
23/// - [`ReadMassProperties`]
24/// - [`ReadWorldMassProperties`]
25/// - [`Damping`]
26/// - [`Dominance`]
27/// - [`Ccd`]: Helps prevent fast bodies from tunneling through other moving bodies.
28/// - [`SoftCcd`]
29/// - [`LockedAxes`]
30/// - [`RigidBodyDisabled`]
31/// - [`GravityScale`]
32/// - [`Sleeping`]
33/// - [`AdditionalSolverIterations`]
34/// - [`AdditionalPgsIterations`]
35/// - [`AllowFastRotation`]
36/// - `GyroscopicForces` (3D only)
37#[derive(Copy, Clone, Debug, PartialEq, Eq, Component, Reflect, Default)]
38#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
39#[reflect(Component, Default, PartialEq)]
40#[require(ReadMassProperties)]
41pub enum RigidBody {
42    /// A `RigidBody::Dynamic` body can be affected by all external forces.
43    #[default]
44    Dynamic,
45    /// A `RigidBody::Fixed` body cannot be affected by external forces.
46    Fixed,
47    /// A `RigidBody::KinematicPositionBased` body cannot be affected by any external forces but can be controlled
48    /// by the user at the position level while keeping realistic one-way interaction with dynamic bodies.
49    ///
50    /// One-way interaction means that a kinematic body can push a dynamic body, but a kinematic body
51    /// cannot be pushed by anything. In other words, the trajectory of a kinematic body can only be
52    /// modified by the user and is independent from any contact or joint it is involved in.
53    KinematicPositionBased,
54    /// A `RigidBody::KinematicVelocityBased` body cannot be affected by any external forces but can be controlled
55    /// by the user at the velocity level while keeping realistic one-way interaction with dynamic bodies.
56    ///
57    /// One-way interaction means that a kinematic body can push a dynamic body, but a kinematic body
58    /// cannot be pushed by anything. In other words, the trajectory of a kinematic body can only be
59    /// modified by the user and is independent from any contact or joint it is involved in.
60    KinematicVelocityBased,
61}
62
63impl From<RigidBody> for RigidBodyType {
64    fn from(rigid_body: RigidBody) -> RigidBodyType {
65        match rigid_body {
66            RigidBody::Dynamic => RigidBodyType::Dynamic,
67            RigidBody::Fixed => RigidBodyType::Fixed,
68            RigidBody::KinematicPositionBased => RigidBodyType::KinematicPositionBased,
69            RigidBody::KinematicVelocityBased => RigidBodyType::KinematicVelocityBased,
70        }
71    }
72}
73
74impl From<RigidBodyType> for RigidBody {
75    fn from(rigid_body: RigidBodyType) -> RigidBody {
76        match rigid_body {
77            // Soft-body cluster proxies are simulated like dynamic bodies.
78            RigidBodyType::Dynamic | RigidBodyType::SoftFrame => RigidBody::Dynamic,
79            RigidBodyType::Fixed => RigidBody::Fixed,
80            RigidBodyType::KinematicPositionBased => RigidBody::KinematicPositionBased,
81            RigidBodyType::KinematicVelocityBased => RigidBody::KinematicVelocityBased,
82        }
83    }
84}
85
86/// The velocity of a [`RigidBody`].
87///
88/// Use this component to control and/or read the velocity of a dynamic or kinematic [`RigidBody`].
89/// If this component isn’t present, a dynamic [`RigidBody`] will still be able to move (you will just
90/// not be able to read/modify its velocity).
91///
92/// This only affects entities with a [`RigidBody`] component.
93#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
94#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
95#[reflect(Component, Default, PartialEq)]
96pub struct Velocity {
97    /// The linear velocity of the [`RigidBody`].
98    pub linear: Vect,
99    /// The angular velocity of the [`RigidBody`] in radian per second.
100    #[cfg(feature = "dim2")]
101    pub angular: f32,
102    /// The angular velocity of the [`RigidBody`].
103    #[cfg(feature = "dim3")]
104    pub angular: Vect,
105}
106
107impl Velocity {
108    /// Initialize a velocity set to zero.
109    pub const fn zero() -> Self {
110        Self {
111            linear: Vect::ZERO,
112            #[cfg(feature = "dim2")]
113            angular: 0.0,
114            #[cfg(feature = "dim3")]
115            angular: Vect::ZERO,
116        }
117    }
118
119    /// Initialize a velocity with the given linear velocity, and an angular velocity of zero.
120    pub const fn linear(linear: Vect) -> Self {
121        Self {
122            linear,
123            #[cfg(feature = "dim2")]
124            angular: 0.0,
125            #[cfg(feature = "dim3")]
126            angular: Vect::ZERO,
127        }
128    }
129
130    /// Initialize a velocity with the given angular velocity, and a linear velocity of zero.
131    #[cfg(feature = "dim2")]
132    pub const fn angular(angular: f32) -> Self {
133        Self {
134            linear: Vect::ZERO,
135            angular,
136        }
137    }
138
139    /// Initialize a velocity with the given angular velocity, and a linear velocity of zero.
140    #[cfg(feature = "dim3")]
141    pub const fn angular(angular: Vect) -> Self {
142        Self {
143            linear: Vect::ZERO,
144            angular,
145        }
146    }
147
148    /// Get linear velocity of specific world-space point of a [`RigidBody`].
149    ///
150    /// # Parameters
151    /// - `point`: the point (world-space) to compute the velocity for.
152    /// - `center_of_mass`: the center-of-mass (world-space) of the [`RigidBody`] the velocity belongs to.
153    pub fn linear_velocity_at_point(&self, point: Vect, center_of_mass: Vect) -> Vect {
154        #[cfg(feature = "dim2")]
155        return self.linear + self.angular * (point - center_of_mass).perp();
156
157        #[cfg(feature = "dim3")]
158        return self.linear + self.angular.cross(point - center_of_mass);
159    }
160}
161
162/// Mass-properties of a [`RigidBody`], added to the contributions of its attached colliders.
163///
164/// This only affects entities with a [`RigidBody`] component.
165#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
166#[reflect(Component, Default, PartialEq)]
167pub enum AdditionalMassProperties {
168    /// This mass will be added to the [`RigidBody`]. The rigid-body’s total
169    /// angular inertia tensor (obtained from its attached colliders) will
170    /// be scaled accordingly.
171    Mass(f32),
172    /// These mass properties will be added to the [`RigidBody`].
173    MassProperties(MassProperties),
174}
175
176impl Default for AdditionalMassProperties {
177    fn default() -> Self {
178        Self::MassProperties(MassProperties::default())
179    }
180}
181
182/// Center-of-mass, mass, and angular inertia.
183///
184/// When this is used as a component, this lets you read the total mass properties of
185/// a [`RigidBody`] (including the colliders contribution). Modifying this component won’t
186/// affect the mass-properties of the [`RigidBody`] (the attached colliders’ `ColliderMassProperties`
187/// and the `AdditionalMassProperties` should be modified instead).
188///
189/// This only reads the mass from entities with a [`RigidBody`] component. It is inserted
190/// automatically with [`RigidBody`] (like the joint read-backs), since it is only updated when
191/// the mass properties change.
192#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
193#[reflect(Component, Default, PartialEq)]
194pub struct ReadMassProperties(MassProperties);
195
196impl ReadMassProperties {
197    /// Get the [`MassProperties`] of this [`RigidBody`].
198    pub fn get(&self) -> &MassProperties {
199        &self.0
200    }
201
202    pub(crate) fn set(&mut self, mass_props: MassProperties) {
203        self.0 = mass_props;
204    }
205}
206
207impl std::ops::Deref for ReadMassProperties {
208    type Target = MassProperties;
209    fn deref(&self) -> &Self::Target {
210        self.get()
211    }
212}
213
214/// World-space and locked-axes-aware mass properties of a [`RigidBody`].
215///
216/// When this is used as a component, it is updated after each physics step to reflect the
217/// current state of the [`RigidBody`]. Modifying this component has no effect on the simulation.
218///
219/// This only reads the mass properties from entities with a [`RigidBody`] component. Unlike
220/// [`ReadMassProperties`], it must be added manually: it changes at every step for every moving
221/// body (its center of mass moves), so, like [`Velocity`], it is only written back for the bodies
222/// that ask for it.
223#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
224#[reflect(Component, Default, PartialEq)]
225pub struct ReadWorldMassProperties {
226    /// The world-space center of mass of the [`RigidBody`].
227    pub center_of_mass: Vect,
228    /// The inverse mass along each world axis, set to zero along locked translation axes.
229    ///
230    /// This is zero for non-dynamic rigid-bodies.
231    pub effective_inv_mass: Vect,
232    /// The world-space inverse angular inertia, set to zero if rotations are locked.
233    ///
234    /// This is zero for non-dynamic rigid-bodies.
235    #[cfg(feature = "dim2")]
236    pub effective_world_inv_inertia: f32,
237    /// The world-space inverse angular inertia tensor, with the rows and columns of locked
238    /// rotation axes set to zero.
239    ///
240    /// This is zero for non-dynamic rigid-bodies.
241    #[cfg(feature = "dim3")]
242    pub effective_world_inv_inertia: Mat3,
243}
244
245impl ReadWorldMassProperties {
246    /// Extracts the world-space mass properties from Rapier’s `RigidBodyMassProps` structure.
247    pub fn from_rapier(mprops: &rapier::dynamics::RigidBodyMassProps) -> Self {
248        #[cfg(feature = "dim3")]
249        let effective_world_inv_inertia = {
250            let i = &mprops.effective_world_inv_inertia;
251            Mat3::from_cols(
252                Vec3::new(i.m11, i.m12, i.m13),
253                Vec3::new(i.m12, i.m22, i.m23),
254                Vec3::new(i.m13, i.m23, i.m33),
255            )
256        };
257        #[cfg(feature = "dim2")]
258        let effective_world_inv_inertia = mprops.effective_world_inv_inertia;
259
260        Self {
261            center_of_mass: mprops.world_com,
262            effective_inv_mass: mprops.effective_inv_mass,
263            effective_world_inv_inertia,
264        }
265    }
266}
267
268/// Entity that likely had their mass properties changed this frame.
269#[derive(Deref, Copy, Clone, Debug, PartialEq, Message)]
270pub struct MassModifiedMessage(pub Entity);
271
272impl From<Entity> for MassModifiedMessage {
273    fn from(entity: Entity) -> Self {
274        Self(entity)
275    }
276}
277
278#[deprecated(
279    since = "0.32.0",
280    note = "MassModifiedMessage has been renamed to MassModifiedEvent for consistency with Bevy 0.17 naming conventions. "
281)]
282pub use MassModifiedMessage as MassModifiedEvent;
283
284/// Center-of-mass, mass, and angular inertia.
285///
286/// This cannot be used as a component. Use the components `ReadMassProperties` to read a [`RigidBody`]’s
287/// mass-properties or `AdditionalMassProperties` to set its additional mass-properties.
288#[derive(Copy, Clone, Debug, Default, PartialEq, Reflect)]
289#[reflect(Default, PartialEq)]
290pub struct MassProperties {
291    /// The center of mass of a [`RigidBody`] expressed in its local-space.
292    pub local_center_of_mass: Vect,
293    /// The mass of a [`RigidBody`].
294    pub mass: f32,
295    /// The principal angular inertia of the [`RigidBody`].
296    #[cfg(feature = "dim2")]
297    pub principal_inertia: f32,
298    /// The principal vectors of the local angular inertia tensor of the [`RigidBody`].
299    #[cfg(feature = "dim3")]
300    pub principal_inertia_local_frame: crate::math::Rot,
301    /// The principal angular inertia of the [`RigidBody`].
302    #[cfg(feature = "dim3")]
303    pub principal_inertia: Vect,
304}
305
306impl MassProperties {
307    /// Converts these mass-properties to Rapier’s `MassProperties` structure.
308    #[cfg(feature = "dim2")]
309    pub fn into_rapier(self) -> rapier::dynamics::MassProperties {
310        rapier::dynamics::MassProperties::new(
311            self.local_center_of_mass,
312            self.mass,
313            #[allow(clippy::useless_conversion)] // Need to convert if dim3 enabled
314            self.principal_inertia.into(),
315        )
316    }
317
318    /// Converts these mass-properties to Rapier’s `MassProperties` structure.
319    #[cfg(feature = "dim3")]
320    pub fn into_rapier(self) -> rapier::dynamics::MassProperties {
321        rapier::dynamics::MassProperties::with_principal_inertia_frame(
322            self.local_center_of_mass,
323            self.mass,
324            self.principal_inertia,
325            self.principal_inertia_local_frame,
326        )
327    }
328
329    /// Converts Rapier’s `MassProperties` structure to `Self`.
330    pub fn from_rapier(mprops: rapier::dynamics::MassProperties) -> Self {
331        #[allow(clippy::useless_conversion)] // Need to convert if dim3 enabled
332        Self {
333            mass: mprops.mass(),
334            local_center_of_mass: mprops.local_com.into(),
335            principal_inertia: mprops.principal_inertia().into(),
336            #[cfg(feature = "dim3")]
337            principal_inertia_local_frame: mprops.principal_inertia_local_frame.into(),
338        }
339    }
340}
341
342#[derive(Default, Debug, Component, Reflect, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
343#[reflect(Component, Default, PartialEq)]
344/// Flags affecting the behavior of the constraints solver for a given contact manifold.
345pub struct LockedAxes(u8);
346
347bitflags::bitflags! {
348    impl LockedAxes: u8 {
349        /// Flag indicating that the [`RigidBody`] cannot translate along the `X` axis.
350        const TRANSLATION_LOCKED_X = 1 << 0;
351        /// Flag indicating that the [`RigidBody`] cannot translate along the `Y` axis.
352        const TRANSLATION_LOCKED_Y = 1 << 1;
353        /// Flag indicating that the [`RigidBody`] cannot translate along the `Z` axis.
354        const TRANSLATION_LOCKED_Z = 1 << 2;
355        /// Flag indicating that the [`RigidBody`] cannot translate along any direction.
356        const TRANSLATION_LOCKED = Self::TRANSLATION_LOCKED_X.bits() | Self::TRANSLATION_LOCKED_Y.bits() | Self::TRANSLATION_LOCKED_Z.bits();
357        /// Flag indicating that the [`RigidBody`] cannot rotate along the `X` axis.
358        const ROTATION_LOCKED_X = 1 << 3;
359        /// Flag indicating that the [`RigidBody`] cannot rotate along the `Y` axis.
360        const ROTATION_LOCKED_Y = 1 << 4;
361        /// Flag indicating that the [`RigidBody`] cannot rotate along the `Z` axis.
362        const ROTATION_LOCKED_Z = 1 << 5;
363        /// Combination of flags indicating that the [`RigidBody`] cannot rotate along any axis.
364        const ROTATION_LOCKED = Self::ROTATION_LOCKED_X.bits() | Self::ROTATION_LOCKED_Y.bits() | Self::ROTATION_LOCKED_Z.bits();
365    }
366}
367
368impl From<LockedAxes> for RapierLockedAxes {
369    fn from(locked_axes: LockedAxes) -> RapierLockedAxes {
370        RapierLockedAxes::from_bits(locked_axes.bits()).expect("Internal conversion error.")
371    }
372}
373
374/// Constant external forces applied continuously to a [`RigidBody`].
375///
376/// This force is applied at each timestep.
377#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
378#[reflect(Component, Default, PartialEq)]
379pub struct ExternalForce {
380    /// The linear force applied to the [`RigidBody`].
381    pub force: Vect,
382    /// The angular torque applied to the [`RigidBody`].
383    #[cfg(feature = "dim2")]
384    pub torque: f32,
385    /// The angular torque applied to the [`RigidBody`].
386    #[cfg(feature = "dim3")]
387    pub torque: Vect,
388}
389
390impl ExternalForce {
391    /// A force applied at a specific world-space point of a [`RigidBody`].
392    ///
393    /// # Parameters
394    /// - `force`: the force to apply.
395    /// - `point`: the point (world-space) where the impulse must be applied.
396    /// - `center_of_mass`: the center-of-mass (world-space) of the [`RigidBody`] the impulse is being
397    ///   applied to.
398    pub fn at_point(force: Vect, point: Vect, center_of_mass: Vect) -> Self {
399        Self {
400            force,
401            #[cfg(feature = "dim2")]
402            torque: (point - center_of_mass).perp_dot(force),
403            #[cfg(feature = "dim3")]
404            torque: (point - center_of_mass).cross(force),
405        }
406    }
407}
408
409impl Add for ExternalForce {
410    type Output = Self;
411
412    #[inline]
413    fn add(mut self, rhs: Self) -> Self::Output {
414        self += rhs;
415        self
416    }
417}
418
419impl Sub for ExternalForce {
420    type Output = Self;
421
422    #[inline]
423    fn sub(mut self, rhs: Self) -> Self::Output {
424        self -= rhs;
425        self
426    }
427}
428
429impl AddAssign for ExternalForce {
430    #[inline]
431    fn add_assign(&mut self, rhs: Self) {
432        self.force += rhs.force;
433        self.torque += rhs.torque;
434    }
435}
436
437impl SubAssign for ExternalForce {
438    #[inline]
439    fn sub_assign(&mut self, rhs: Self) {
440        self.force -= rhs.force;
441        self.torque -= rhs.torque;
442    }
443}
444
445/// Instantaneous external impulse applied continuously to a [`RigidBody`].
446///
447/// The impulse is only applied once, and whenever it it modified (based
448/// on Bevy’s change detection).
449#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
450#[reflect(Component, Default, PartialEq)]
451pub struct ExternalImpulse {
452    /// The linear impulse applied to the [`RigidBody`].
453    pub impulse: Vect,
454    /// The angular impulse applied to the [`RigidBody`].
455    #[cfg(feature = "dim2")]
456    pub torque_impulse: f32,
457    /// The angular impulse applied to the [`RigidBody`].
458    #[cfg(feature = "dim3")]
459    pub torque_impulse: Vect,
460}
461
462impl ExternalImpulse {
463    /// An impulse applied at a specific world-space point of a [`RigidBody`].
464    ///
465    /// # Parameters
466    /// - `impulse`: the impulse to apply.
467    /// - `point`: the point (world-space) where the impulse must be applied.
468    /// - `center_of_mass`: the center-of-mass (world-space) of the [`RigidBody`] the impulse is being
469    ///   applied to.
470    pub fn at_point(impulse: Vect, point: Vect, center_of_mass: Vect) -> Self {
471        Self {
472            impulse,
473            #[cfg(feature = "dim2")]
474            torque_impulse: (point - center_of_mass).perp_dot(impulse),
475            #[cfg(feature = "dim3")]
476            torque_impulse: (point - center_of_mass).cross(impulse),
477        }
478    }
479
480    /// Reset the external impulses to zero.
481    pub fn reset(&mut self) {
482        *self = Default::default();
483    }
484}
485
486impl Add for ExternalImpulse {
487    type Output = Self;
488
489    #[inline]
490    fn add(mut self, rhs: Self) -> Self::Output {
491        self += rhs;
492        self
493    }
494}
495
496impl Sub for ExternalImpulse {
497    type Output = Self;
498
499    #[inline]
500    fn sub(mut self, rhs: Self) -> Self::Output {
501        self -= rhs;
502        self
503    }
504}
505
506impl AddAssign for ExternalImpulse {
507    #[inline]
508    fn add_assign(&mut self, rhs: Self) {
509        self.impulse += rhs.impulse;
510        self.torque_impulse += rhs.torque_impulse;
511    }
512}
513
514impl SubAssign for ExternalImpulse {
515    #[inline]
516    fn sub_assign(&mut self, rhs: Self) {
517        self.impulse -= rhs.impulse;
518        self.torque_impulse -= rhs.torque_impulse;
519    }
520}
521
522/// Gravity is multiplied by this scaling factor before it's
523/// applied to this [`RigidBody`].
524#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
525#[reflect(Component, Default, PartialEq)]
526pub struct GravityScale(pub f32);
527
528impl Default for GravityScale {
529    fn default() -> Self {
530        Self(1.0)
531    }
532}
533
534/// Enables full ("bullet") Continuous-Collision-Detection for a [`RigidBody`].
535///
536/// Fast dynamic bodies always sweep against fixed colliders automatically (unless
537/// [`IntegrationParameters::max_ccd_substeps`] is `0`), even without this component. Enabling
538/// CCD upgrades the body to also sweep against kinematic and dynamic bodies, at an extra CPU cost.
539/// This is useful for projectiles that must not tunnel through other moving bodies. Note that a
540/// bullet never sweeps another bullet, so two CCD-enabled bodies can still tunnel through each other.
541#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Component, Reflect)]
542#[reflect(Component, Default, PartialEq)]
543pub struct Ccd {
544    /// Is full ("bullet") CCD enabled for this [`RigidBody`]?
545    pub enabled: bool,
546}
547
548impl Ccd {
549    /// Enable CCD for a [`RigidBody`].
550    pub fn enabled() -> Self {
551        Self { enabled: true }
552    }
553
554    /// Disable full CCD for a [`RigidBody`].
555    ///
556    /// Note that a [`RigidBody`] without the Ccd component attached
557    /// has full CCD disabled by default (it still sweeps against fixed colliders when moving fast).
558    pub fn disabled() -> Self {
559        Self { enabled: false }
560    }
561}
562
563/// Sets the maximum prediction distance Soft Continuous Collision-Detection.
564///
565/// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
566/// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
567/// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
568/// performance badly by increasing the work needed from the broad-phase.
569///
570/// It is a generally cheaper variant of regular CCD (that can be enabled with
571/// [`Ccd`]) since it relies on predictive constraints instead of shape-cast and substeps.
572#[derive(Copy, Clone, Debug, Default, PartialEq, Component, Reflect)]
573#[reflect(Component, Default, PartialEq)]
574pub struct SoftCcd {
575    /// The soft CCD prediction distance.
576    pub prediction: f32,
577}
578
579/// The dominance groups of a [`RigidBody`].
580#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Component, Reflect)]
581#[reflect(Component, Default, PartialEq)]
582pub struct Dominance {
583    // FIXME: rename this to `group` (no `s`).
584    /// The dominance groups of a [`RigidBody`].
585    pub groups: i8,
586}
587
588impl Dominance {
589    /// Initialize the dominance to the given group.
590    pub fn group(group: i8) -> Self {
591        Self { groups: group }
592    }
593}
594
595/// The activation status of a body.
596///
597/// This controls whether a body is sleeping or not.
598/// If the threshold is negative, the body never sleeps.
599///
600/// Setting `sleeping` to `false` on a sleeping body wakes up its whole island (every body
601/// connected to it through contacts or joints).
602#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
603#[reflect(Component, Default, PartialEq)]
604pub struct Sleeping {
605    /// The linear velocity below which the body can fall asleep.
606    ///
607    /// The effictive threshold is obtained by multpilying this value by the
608    /// [`IntegrationParameters::length_unit`].
609    pub normalized_linear_threshold: f32,
610    /// The angular velocity below which the body can fall asleep.
611    pub angular_threshold: f32,
612    /// How long (in seconds) the body must remain below the velocity thresholds before
613    /// falling asleep.
614    pub time_until_sleep: f32,
615    /// Is this body sleeping?
616    pub sleeping: bool,
617}
618
619impl Sleeping {
620    /// Creates a components that disables sleeping for the associated [`RigidBody`].
621    pub fn disabled() -> Self {
622        Self {
623            normalized_linear_threshold: -1.0,
624            angular_threshold: -1.0,
625            time_until_sleep: RigidBodyActivation::default_time_until_sleep(),
626            sleeping: false,
627        }
628    }
629}
630
631impl Default for Sleeping {
632    fn default() -> Self {
633        Self {
634            normalized_linear_threshold: RigidBodyActivation::default_normalized_linear_threshold(),
635            angular_threshold: RigidBodyActivation::default_angular_threshold(),
636            time_until_sleep: RigidBodyActivation::default_time_until_sleep(),
637            sleeping: false,
638        }
639    }
640}
641
642/// Damping factors to gradually slow down a [`RigidBody`].
643#[derive(Copy, Clone, Debug, PartialEq, Component, Reflect)]
644#[reflect(Component, Default, PartialEq)]
645pub struct Damping {
646    // TODO: rename these to "linear" and "angular"?
647    /// Damping factor for gradually slowing down the translational motion of the [`RigidBody`].
648    pub linear_damping: f32,
649    /// Damping factor for gradually slowing down the angular motion of the [`RigidBody`].
650    pub angular_damping: f32,
651}
652
653impl Default for Damping {
654    fn default() -> Self {
655        Self {
656            linear_damping: 0.0,
657            angular_damping: 0.0,
658        }
659    }
660}
661
662/// If the `TimestepMode::Interpolated` mode is set and this component is present,
663/// the associated [`RigidBody`] will have its position automatically interpolated
664/// between the last two [`RigidBody`] positions set by the physics engine.
665#[derive(Copy, Clone, Debug, Default, PartialEq, Component)]
666pub struct TransformInterpolation {
667    /// The starting point of the interpolation.
668    pub start: Option<Pose>,
669    /// The end point of the interpolation.
670    pub end: Option<Pose>,
671}
672
673impl TransformInterpolation {
674    /// Interpolates between the start and end positions with `t` in the range `[0..1]`.
675    pub fn lerp_slerp(&self, t: f32) -> Option<Pose> {
676        if let (Some(start), Some(end)) = (self.start, self.end) {
677            Some(start.lerp(&end, t))
678        } else {
679            None
680        }
681    }
682}
683
684/// Indicates whether or not the [`RigidBody`] is disabled explicitly by the user.
685#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
686#[reflect(Component, Default, PartialEq)]
687pub struct RigidBodyDisabled;
688
689/// Set the additional number of solver substeps run for the simulation island containing this
690/// rigid-body.
691///
692/// Each extra substep re-derives the soft constraint bias at a smaller timestep, improving
693/// accuracy for stiff couplings (joint chains, stacks with high mass ratios). The whole
694/// connected component (every body linked to this one through contacts or joints) runs
695/// [`IntegrationParameters::num_solver_iterations`] plus the largest
696/// `AdditionalSolverIterations` among its bodies substeps. The cost thus scales with the size
697/// of that component: attaching such a body to a large pile also substeps the whole pile.
698///
699/// The default value is 0, meaning exactly [`IntegrationParameters::num_solver_iterations`]
700/// substeps will be used for this body.
701#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
702#[reflect(Component, Default, PartialEq)]
703pub struct AdditionalSolverIterations(pub usize);
704
705/// Set the additional number of internal PGS iterations run at each substep for the simulation
706/// island containing this rigid-body.
707///
708/// The whole connected component (every body linked to this one through contacts or joints)
709/// runs [`IntegrationParameters::num_internal_pgs_iterations`] plus the largest
710/// `AdditionalPgsIterations` among its bodies. The default value is 0.
711#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
712#[reflect(Component, Default, PartialEq)]
713pub struct AdditionalPgsIterations(pub usize);
714
715/// Allows the [`RigidBody`] to exceed the angular speed cap.
716///
717/// By default, the angular velocity of a rigid-body is clamped at each substep (to roughly
718/// 45 degrees per step) to keep CCD reliable. Add this marker to bodies that must spin fast,
719/// e.g., wheels. Removing it restores the cap.
720#[derive(Copy, Clone, Default, Debug, PartialEq, Eq, Component, Reflect)]
721#[reflect(Component, Default, PartialEq)]
722pub struct AllowFastRotation;
723
724/// Enables or disables gyroscopic forces on a [`RigidBody`].
725///
726/// Gyroscopic forces make spinning bodies resist changes of their rotation axis (e.g.,
727/// spinning tops or flywheels), at a slight performance cost. Rapier enables them by default,
728/// so a rigid-body without this component has gyroscopic forces enabled.
729#[cfg(feature = "dim3")]
730#[derive(Copy, Clone, Debug, PartialEq, Eq, Component, Reflect)]
731#[reflect(Component, Default, PartialEq)]
732pub struct GyroscopicForces {
733    /// Are gyroscopic forces enabled for this [`RigidBody`]?
734    pub enabled: bool,
735}
736
737#[cfg(feature = "dim3")]
738impl GyroscopicForces {
739    /// Enable gyroscopic forces for a [`RigidBody`].
740    pub fn enabled() -> Self {
741        Self { enabled: true }
742    }
743
744    /// Disable gyroscopic forces for a [`RigidBody`].
745    pub fn disabled() -> Self {
746        Self { enabled: false }
747    }
748}
749
750#[cfg(feature = "dim3")]
751impl Default for GyroscopicForces {
752    fn default() -> Self {
753        Self::enabled()
754    }
755}