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}