Skip to main content

rapier2d/dynamics/
rigid_body.rs

1use crate::alloc_prelude::*;
2#[cfg(all(not(feature = "std"), feature = "dim3"))]
3use simba::scalar::ComplexField;
4
5#[cfg(doc)]
6use super::IntegrationParameters;
7use crate::dynamics::{
8    LockedAxes, MassProperties, RigidBodyActivation, RigidBodyAdditionalMassProps, RigidBodyCcd,
9    RigidBodyChanges, RigidBodyColliders, RigidBodyDamping, RigidBodyDominance, RigidBodyForces,
10    RigidBodyIds, RigidBodyMassProps, RigidBodyPosition, RigidBodyType, RigidBodyVelocity,
11};
12use crate::geometry::{
13    ColliderHandle, ColliderMassProps, ColliderParent, ColliderPosition, ColliderSet, ColliderShape,
14};
15use crate::math::{AngVector, Pose, Real, Rotation, Vector, rotation_from_angle};
16use crate::utils::CrossProduct;
17
18#[cfg(feature = "dim2")]
19use crate::num::Zero;
20
21#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))]
22/// A physical object that can move, rotate, and collide with other objects in your simulation.
23///
24/// Rigid bodies are the fundamental moving objects in physics simulations. Think of them as
25/// the "physical representation" of your game objects - a character, a crate, a vehicle, etc.
26///
27/// ## Body types
28///
29/// - **Dynamic**: Affected by forces, gravity, and collisions. Use for objects that should move realistically (falling boxes, projectiles, etc.)
30/// - **Fixed**: Never moves. Use for static geometry like walls, floors, and terrain
31/// - **Kinematic**: Moved by setting velocity or position directly, not by forces. Use for moving platforms, doors, or player-controlled characters
32///
33/// ## Creating bodies
34///
35/// Always use [`RigidBodyBuilder`] to create new rigid bodies:
36///
37/// ```
38/// # use rapier3d::prelude::*;
39/// # let mut bodies = RigidBodySet::new();
40/// let body = RigidBodyBuilder::dynamic()
41///     .translation(Vector::new(0.0, 10.0, 0.0))
42///     .build();
43/// let handle = bodies.insert(body);
44/// ```
45#[derive(Debug, Clone)]
46// #[repr(C)]
47// #[repr(align(64))]
48pub struct RigidBody {
49    pub(crate) ids: RigidBodyIds,
50    pub(crate) pos: RigidBodyPosition,
51    pub(crate) damping: RigidBodyDamping<Real>,
52    pub(crate) vels: RigidBodyVelocity<Real>,
53    pub(crate) forces: RigidBodyForces,
54    pub(crate) mprops: RigidBodyMassProps,
55
56    pub(crate) ccd_vels: RigidBodyVelocity<Real>,
57    pub(crate) ccd: RigidBodyCcd,
58    pub(crate) colliders: RigidBodyColliders,
59    /// Whether or not this rigid-body is sleeping.
60    pub(crate) activation: RigidBodyActivation,
61    pub(crate) changes: RigidBodyChanges,
62    /// The status of the body, governing how it is affected by external forces.
63    pub(crate) body_type: RigidBodyType,
64    /// The dominance group this rigid-body is part of.
65    pub(crate) dominance: RigidBodyDominance,
66    pub(crate) enabled: bool,
67    pub(crate) additional_solver_iterations: usize,
68    /// User-defined data associated to this rigid-body.
69    pub user_data: u128,
70}
71
72impl Default for RigidBody {
73    fn default() -> Self {
74        Self::new()
75    }
76}
77
78impl RigidBody {
79    fn new() -> Self {
80        Self {
81            pos: RigidBodyPosition::default(),
82            mprops: RigidBodyMassProps::default(),
83            ccd_vels: RigidBodyVelocity::default(),
84            vels: RigidBodyVelocity::default(),
85            damping: RigidBodyDamping::default(),
86            forces: RigidBodyForces::default(),
87            ccd: RigidBodyCcd::default(),
88            ids: RigidBodyIds::default(),
89            colliders: RigidBodyColliders::default(),
90            activation: RigidBodyActivation::active(),
91            changes: RigidBodyChanges::all(),
92            body_type: RigidBodyType::Dynamic,
93            dominance: RigidBodyDominance::default(),
94            enabled: true,
95            user_data: 0,
96            additional_solver_iterations: 0,
97        }
98    }
99
100    pub(crate) fn reset_internal_references(&mut self) {
101        self.colliders.0 = Vec::new();
102        self.ids = Default::default();
103    }
104
105    /// Copy all the characteristics from `other` to `self`.
106    ///
107    /// If you have a mutable reference to a rigid-body `rigid_body: &mut RigidBody`, attempting to
108    /// assign it a whole new rigid-body instance, e.g., `*rigid_body = RigidBodyBuilder::dynamic().build()`,
109    /// will crash due to some internal indices being overwritten. Instead, use
110    /// `rigid_body.copy_from(&RigidBodyBuilder::dynamic().build())`.
111    ///
112    /// This method will allow you to set most characteristics of this rigid-body from another
113    /// rigid-body instance without causing any breakage.
114    ///
115    /// This method **cannot** be used for editing the list of colliders attached to this rigid-body.
116    /// Therefore, the list of colliders attached to `self` won’t be replaced by the one attached
117    /// to `other`.
118    ///
119    /// The pose of `other` will only copied into `self` if `self` doesn’t have a parent (if it has
120    /// a parent, its position is directly controlled by the parent rigid-body).
121    pub fn copy_from(&mut self, other: &RigidBody) {
122        // NOTE: we deconstruct the rigid-body struct to be sure we don’t forget to
123        //       add some copies here if we add more field to RigidBody in the future.
124        let RigidBody {
125            pos,
126            mprops,
127            ccd_vels: integrated_vels,
128            vels,
129            damping,
130            forces,
131            ccd,
132            ids: _ids,             // Internal ids must not be overwritten.
133            colliders: _colliders, // This function cannot be used to edit collider sets.
134            activation,
135            changes: _changes, // Will be set to ALL.
136            body_type,
137            dominance,
138            enabled,
139            additional_solver_iterations,
140            user_data,
141        } = other;
142
143        self.pos = *pos;
144        self.mprops = mprops.clone();
145        self.ccd_vels = *integrated_vels;
146        self.vels = *vels;
147        self.damping = *damping;
148        self.forces = *forces;
149        self.ccd = *ccd;
150        self.activation = *activation;
151        self.body_type = *body_type;
152        self.dominance = *dominance;
153        self.enabled = *enabled;
154        self.additional_solver_iterations = *additional_solver_iterations;
155        self.user_data = *user_data;
156
157        self.changes = RigidBodyChanges::all();
158    }
159
160    /// The additional number of solver iterations run for the constraints directly
161    /// involving this rigid-body.
162    ///
163    /// See [`Self::set_additional_solver_iterations`] for additional information.
164    pub fn additional_solver_iterations(&self) -> usize {
165        self.additional_solver_iterations
166    }
167
168    /// Set the additional number of solver substeps run for the simulation island containing this
169    /// rigid-body (default: 0). Each extra substep re-derives the soft constraint bias at a smaller
170    /// timestep, improving accuracy for stiff couplings (joint chains, high mass-ratio stacks). The
171    /// whole connected component (contacts + joints) runs `num_solver_iterations +
172    /// max(additional_solver_iterations)` substeps, so the cost scales with component size —
173    /// attaching an elevated body to a large pile substeps the pile too.
174    pub fn set_additional_solver_iterations(&mut self, additional_iterations: usize) {
175        self.additional_solver_iterations = additional_iterations;
176    }
177
178    /// The activation status of this rigid-body.
179    pub fn activation(&self) -> &RigidBodyActivation {
180        &self.activation
181    }
182
183    /// Mutable reference to the activation status of this rigid-body.
184    pub fn activation_mut(&mut self) -> &mut RigidBodyActivation {
185        self.changes |= RigidBodyChanges::SLEEP;
186        &mut self.activation
187    }
188
189    /// Is this rigid-body enabled?
190    pub fn is_enabled(&self) -> bool {
191        self.enabled
192    }
193
194    /// Sets whether this rigid-body is enabled or not.
195    pub fn set_enabled(&mut self, enabled: bool) {
196        if enabled != self.enabled {
197            if enabled {
198                // NOTE: this is probably overkill, but it makes sure we don’t
199                // forget anything that needs to be updated because the rigid-body
200                // was basically interpreted as if it was removed while it was
201                // disabled.
202                self.changes = RigidBodyChanges::all();
203            } else {
204                self.changes |= RigidBodyChanges::ENABLED_OR_DISABLED;
205            }
206
207            self.enabled = enabled;
208        }
209    }
210
211    /// The linear damping coefficient (velocity reduction over time).
212    ///
213    /// Damping gradually slows down moving objects. `0.0` = no damping (infinite momentum),
214    /// higher values = faster slowdown. Use for air resistance, friction, etc.
215    #[inline]
216    pub fn linear_damping(&self) -> Real {
217        self.damping.linear_damping
218    }
219
220    /// Sets how quickly linear velocity decreases over time.
221    ///
222    /// - `0.0` = no slowdown (space/frictionless)
223    /// - `0.1` = gradual slowdown (air resistance)
224    /// - `1.0+` = rapid slowdown (thick fluid)
225    #[inline]
226    pub fn set_linear_damping(&mut self, damping: Real) {
227        self.damping.linear_damping = damping;
228    }
229
230    /// The angular damping coefficient (rotation slowdown over time).
231    ///
232    /// Like linear damping but for rotation. Higher values make spinning objects stop faster.
233    #[inline]
234    pub fn angular_damping(&self) -> Real {
235        self.damping.angular_damping
236    }
237
238    /// Sets how quickly angular velocity decreases over time.
239    ///
240    /// Controls how fast spinning objects slow down.
241    #[inline]
242    pub fn set_angular_damping(&mut self, damping: Real) {
243        self.damping.angular_damping = damping
244    }
245
246    /// The type of this rigid-body.
247    pub fn body_type(&self) -> RigidBodyType {
248        self.body_type
249    }
250
251    /// Sets the type of this rigid-body.
252    pub fn set_body_type(&mut self, status: RigidBodyType, wake_up: bool) {
253        if status != self.body_type {
254            self.changes.insert(RigidBodyChanges::TYPE);
255            self.body_type = status;
256
257            if status == RigidBodyType::Fixed {
258                self.vels = RigidBodyVelocity::zero();
259            }
260
261            // The effective mass-properties depend on the body type (kinematic and
262            // fixed bodies have zero effective inverse masses).
263            self.update_world_mass_properties();
264
265            if self.is_dynamic_or_kinematic() && wake_up {
266                self.wake_up(true);
267            }
268        }
269    }
270
271    /// The center of mass position in world coordinates.
272    ///
273    /// This is the "balance point" where the body's mass is centered. Forces applied here
274    /// produce no rotation, only translation.
275    #[inline]
276    pub fn center_of_mass(&self) -> Vector {
277        self.mprops.world_com
278    }
279
280    /// The center of mass in the body's local coordinate system.
281    ///
282    /// This is relative to the body's position, computed from attached colliders.
283    #[inline]
284    pub fn local_center_of_mass(&self) -> Vector {
285        self.mprops.local_mprops.local_com
286    }
287
288    /// The mass-properties of this rigid-body.
289    #[inline]
290    pub fn mass_properties(&self) -> &RigidBodyMassProps {
291        &self.mprops
292    }
293
294    /// The dominance group of this rigid-body.
295    ///
296    /// This method always returns `i8::MAX + 1` for non-dynamic
297    /// rigid-bodies.
298    #[inline]
299    pub fn effective_dominance_group(&self) -> i16 {
300        self.dominance.effective_group(&self.body_type)
301    }
302
303    /// Sets the axes along which this rigid-body cannot translate or rotate.
304    #[inline]
305    pub fn set_locked_axes(&mut self, locked_axes: LockedAxes, wake_up: bool) {
306        if locked_axes != self.mprops.flags {
307            if self.is_dynamic_or_kinematic() && wake_up {
308                self.wake_up(true);
309            }
310
311            self.mprops.flags = locked_axes;
312            self.update_world_mass_properties();
313        }
314    }
315
316    /// The axes along which this rigid-body cannot translate or rotate.
317    #[inline]
318    pub fn locked_axes(&self) -> LockedAxes {
319        self.mprops.flags
320    }
321
322    /// Locks or unlocks all rotational movement for this body.
323    ///
324    /// When locked, the body cannot rotate at all (useful for keeping objects upright).
325    /// Use for characters that shouldn't tip over, or objects that should only slide.
326    #[inline]
327    pub fn lock_rotations(&mut self, locked: bool, wake_up: bool) {
328        if locked != self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED) {
329            if self.is_dynamic_or_kinematic() && wake_up {
330                self.wake_up(true);
331            }
332
333            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_X, locked);
334            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_Y, locked);
335            self.mprops.flags.set(LockedAxes::ROTATION_LOCKED_Z, locked);
336            self.update_world_mass_properties();
337        }
338    }
339
340    #[inline]
341    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
342    pub fn set_enabled_rotations(
343        &mut self,
344        allow_rotations_x: bool,
345        allow_rotations_y: bool,
346        allow_rotations_z: bool,
347        wake_up: bool,
348    ) {
349        if self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_X) == allow_rotations_x
350            || self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Y) == allow_rotations_y
351            || self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z) == allow_rotations_z
352        {
353            if self.is_dynamic_or_kinematic() && wake_up {
354                self.wake_up(true);
355            }
356
357            self.mprops
358                .flags
359                .set(LockedAxes::ROTATION_LOCKED_X, !allow_rotations_x);
360            self.mprops
361                .flags
362                .set(LockedAxes::ROTATION_LOCKED_Y, !allow_rotations_y);
363            self.mprops
364                .flags
365                .set(LockedAxes::ROTATION_LOCKED_Z, !allow_rotations_z);
366            self.update_world_mass_properties();
367        }
368    }
369
370    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
371    #[deprecated(note = "Use `set_enabled_rotations` instead")]
372    pub fn restrict_rotations(
373        &mut self,
374        allow_rotations_x: bool,
375        allow_rotations_y: bool,
376        allow_rotations_z: bool,
377        wake_up: bool,
378    ) {
379        self.set_enabled_rotations(
380            allow_rotations_x,
381            allow_rotations_y,
382            allow_rotations_z,
383            wake_up,
384        );
385    }
386
387    /// Locks or unlocks all translational movement for this body.
388    ///
389    /// When locked, the body cannot move from its position (but can still rotate).
390    /// Use for rotating platforms, turrets, or objects fixed in space.
391    #[inline]
392    pub fn lock_translations(&mut self, locked: bool, wake_up: bool) {
393        if locked != self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED) {
394            if self.is_dynamic_or_kinematic() && wake_up {
395                self.wake_up(true);
396            }
397
398            self.mprops
399                .flags
400                .set(LockedAxes::TRANSLATION_LOCKED, locked);
401            self.update_world_mass_properties();
402        }
403    }
404
405    #[inline]
406    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
407    pub fn set_enabled_translations(
408        &mut self,
409        allow_translation_x: bool,
410        allow_translation_y: bool,
411        #[cfg(feature = "dim3")] allow_translation_z: bool,
412        wake_up: bool,
413    ) {
414        #[cfg(feature = "dim2")]
415        if self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_X) != allow_translation_x
416            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Y) != allow_translation_y
417        {
418            // Nothing to change.
419            return;
420        }
421        #[cfg(feature = "dim3")]
422        if self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_X) != allow_translation_x
423            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Y) != allow_translation_y
424            && self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED_Z) != allow_translation_z
425        {
426            // Nothing to change.
427            return;
428        }
429
430        if self.is_dynamic_or_kinematic() && wake_up {
431            self.wake_up(true);
432        }
433
434        self.mprops
435            .flags
436            .set(LockedAxes::TRANSLATION_LOCKED_X, !allow_translation_x);
437        self.mprops
438            .flags
439            .set(LockedAxes::TRANSLATION_LOCKED_Y, !allow_translation_y);
440        #[cfg(feature = "dim3")]
441        self.mprops
442            .flags
443            .set(LockedAxes::TRANSLATION_LOCKED_Z, !allow_translation_z);
444        self.update_world_mass_properties();
445    }
446
447    #[inline]
448    #[deprecated(note = "Use `set_enabled_translations` instead")]
449    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
450    pub fn restrict_translations(
451        &mut self,
452        allow_translation_x: bool,
453        allow_translation_y: bool,
454        #[cfg(feature = "dim3")] allow_translation_z: bool,
455        wake_up: bool,
456    ) {
457        self.set_enabled_translations(
458            allow_translation_x,
459            allow_translation_y,
460            #[cfg(feature = "dim3")]
461            allow_translation_z,
462            wake_up,
463        )
464    }
465
466    /// Are the translations of this rigid-body locked?
467    #[cfg(feature = "dim2")]
468    pub fn is_translation_locked(&self) -> bool {
469        self.mprops
470            .flags
471            .contains(LockedAxes::TRANSLATION_LOCKED_X | LockedAxes::TRANSLATION_LOCKED_Y)
472    }
473
474    /// Are the translations of this rigid-body locked?
475    #[cfg(feature = "dim3")]
476    pub fn is_translation_locked(&self) -> bool {
477        self.mprops.flags.contains(LockedAxes::TRANSLATION_LOCKED)
478    }
479
480    /// Are the rotations of this rigid-body locked?
481    #[cfg(feature = "dim2")]
482    pub fn is_rotation_locked(&self) -> bool {
483        self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z)
484    }
485
486    /// Returns `true` for each rotational degrees of freedom locked on this rigid-body.
487    #[cfg(feature = "dim3")]
488    pub fn is_rotation_locked(&self) -> [bool; 3] {
489        [
490            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_X),
491            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Y),
492            self.mprops.flags.contains(LockedAxes::ROTATION_LOCKED_Z),
493        ]
494    }
495
496    /// Enables or disables full ("bullet") CCD: fast dynamic bodies already sweep **fixed**
497    /// colliders automatically (unless [`IntegrationParameters::max_ccd_substeps`] is `0`); this
498    /// upgrades the body to also sweep **kinematic and dynamic** bodies at extra CPU cost —
499    /// for projectiles that must not tunnel through other moving bodies. A bullet never
500    /// sweeps another bullet, so two bullets can still tunnel through each other.
501    pub fn enable_ccd(&mut self, enabled: bool) {
502        self.ccd.ccd_enabled = enabled;
503    }
504
505    /// Checks if full ("bullet") CCD is enabled: whether this body sweeps against all bodies
506    /// rather than only fixed colliders. Independent from whether CCD is *active* this frame
507    /// ([`RigidBody::is_ccd_active`]) and from the automatic fixed-collider CCD of fast dynamic bodies.
508    pub fn is_ccd_enabled(&self) -> bool {
509        self.ccd.ccd_enabled
510    }
511
512    /// Sets the maximum prediction distance Soft Continuous Collision-Detection.
513    ///
514    /// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
515    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
516    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
517    /// performance badly by increasing the work needed from the broad-phase.
518    ///
519    /// It is a generally cheaper variant of regular CCD (that can be enabled with
520    /// [`RigidBody::enable_ccd`] since it relies on predictive constraints instead of
521    /// shape-cast and substeps.
522    pub fn set_soft_ccd_prediction(&mut self, prediction_distance: Real) {
523        self.ccd.soft_ccd_prediction = prediction_distance;
524    }
525
526    /// The soft-CCD prediction distance for this rigid-body.
527    ///
528    /// See the documentation of [`RigidBody::set_soft_ccd_prediction`] for additional details on
529    /// soft-CCD.
530    pub fn soft_ccd_prediction(&self) -> Real {
531        self.ccd.soft_ccd_prediction
532    }
533
534    /// Allow (or disallow) this body to exceed the angular speed cap.
535    ///
536    /// By default angular velocity is clamped each substep to ~45°/step to keep CCD reliable;
537    /// pass `true` for bodies that must spin fast, e.g. wheels.
538    pub fn set_allow_fast_rotation(&mut self, allow: bool) {
539        self.ccd.allow_fast_rotation = allow;
540    }
541
542    /// Is this body allowed to exceed the angular speed cap?
543    ///
544    /// See [`RigidBody::set_allow_fast_rotation`].
545    pub fn is_fast_rotation_allowed(&self) -> bool {
546        self.ccd.allow_fast_rotation
547    }
548
549    // This is different from `is_ccd_enabled`. This checks that CCD
550    // is active for this rigid-body, i.e., if it was seen to move fast
551    // enough to justify a CCD run.
552    /// Is CCD active for this rigid-body?
553    ///
554    /// Set for *any* dynamic body moving faster than an automatically-computed threshold (which
555    /// then sweeps fixed colliders), not only bodies with [`RigidBody::is_ccd_enabled`] — which
556    /// only says whether the body is upgraded to sweep all bodies, independently of its velocity.
557    pub fn is_ccd_active(&self) -> bool {
558        self.ccd.ccd_active
559    }
560
561    /// Recalculates mass, center of mass, and inertia from attached colliders.
562    ///
563    /// Normally automatic, but call this if you modify collider shapes/masses at runtime.
564    /// Only needed after directly modifying colliders without going through the builder.
565    pub fn recompute_mass_properties_from_colliders(&mut self, colliders: &ColliderSet) {
566        self.mprops.recompute_mass_properties_from_colliders(
567            colliders,
568            &self.colliders,
569            self.body_type,
570            &self.pos.position,
571        );
572    }
573
574    /// Adds extra mass on top of collider-computed mass.
575    ///
576    /// Total mass = collider masses + this additional mass. Use when you want to make
577    /// a body heavier without changing collider densities.
578    ///
579    /// # Example
580    /// ```
581    /// # use rapier3d::prelude::*;
582    /// # let mut bodies = RigidBodySet::new();
583    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
584    /// // Add 50kg to make this body heavier
585    /// bodies[body].set_additional_mass(50.0, true);
586    /// ```
587    ///
588    /// Angular inertia is automatically scaled to match the mass increase.
589    /// Updated automatically at next physics step or call `recompute_mass_properties_from_colliders()`.
590    #[inline]
591    pub fn set_additional_mass(&mut self, additional_mass: Real, wake_up: bool) {
592        self.do_set_additional_mass_properties(
593            RigidBodyAdditionalMassProps::Mass(additional_mass),
594            wake_up,
595        )
596    }
597
598    /// Sets the rigid-body's additional mass-properties.
599    ///
600    /// This is only the "additional" mass-properties because the total mass-properties of the
601    /// rigid-body is equal to the sum of this additional mass-properties and the mass computed from
602    /// the colliders (with non-zero densities) attached to this rigid-body.
603    ///
604    /// That total mass-properties (which include the attached colliders’ contributions)
605    /// will be updated at the name physics step, or can be updated manually with
606    /// [`Self::recompute_mass_properties_from_colliders`].
607    ///
608    /// This will override any previous mass-properties set by [`Self::set_additional_mass`],
609    /// [`Self::set_additional_mass_properties`], [`RigidBodyBuilder::additional_mass`], or
610    /// [`RigidBodyBuilder::additional_mass_properties`] for this rigid-body.
611    ///
612    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
613    /// put to sleep because it did not move for a while.
614    #[inline]
615    pub fn set_additional_mass_properties(&mut self, props: MassProperties, wake_up: bool) {
616        self.do_set_additional_mass_properties(
617            RigidBodyAdditionalMassProps::MassProps(props),
618            wake_up,
619        )
620    }
621
622    fn do_set_additional_mass_properties(
623        &mut self,
624        props: RigidBodyAdditionalMassProps,
625        wake_up: bool,
626    ) {
627        let new_mprops = Some(Box::new(props));
628
629        if self.mprops.additional_local_mprops != new_mprops {
630            self.changes.insert(RigidBodyChanges::LOCAL_MASS_PROPERTIES);
631            self.mprops.additional_local_mprops = new_mprops;
632
633            if self.is_dynamic_or_kinematic() && wake_up {
634                self.wake_up(true);
635            }
636        }
637    }
638
639    /// Returns handles of all colliders attached to this body.
640    ///
641    /// Use to iterate over a body's collision shapes or to modify them.
642    ///
643    /// # Example
644    /// ```
645    /// # use rapier3d::prelude::*;
646    /// # let mut bodies = RigidBodySet::new();
647    /// # let mut colliders = ColliderSet::new();
648    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
649    /// # colliders.insert_with_parent(ColliderBuilder::ball(0.5), body, &mut bodies);
650    /// for collider_handle in bodies[body].colliders() {
651    ///     if let Some(collider) = colliders.get_mut(*collider_handle) {
652    ///         collider.set_friction(0.5);
653    ///     }
654    /// }
655    /// ```
656    pub fn colliders(&self) -> &[ColliderHandle] {
657        &self.colliders.0[..]
658    }
659
660    /// Checks if this is a dynamic body (moves via forces and collisions).
661    ///
662    /// Dynamic bodies are fully simulated and respond to gravity, forces, and collisions.
663    pub fn is_dynamic(&self) -> bool {
664        self.body_type == RigidBodyType::Dynamic
665    }
666
667    /// Checks if this is a kinematic body (moves via direct velocity/position control).
668    ///
669    /// Kinematic bodies move by setting velocity directly, not by applying forces.
670    pub fn is_kinematic(&self) -> bool {
671        self.body_type.is_kinematic()
672    }
673
674    /// Is this rigid-body a dynamic rigid-body or a kinematic rigid-body?
675    ///
676    /// This method is mostly convenient internally where kinematic and dynamic rigid-body
677    /// are subject to the same behavior.
678    pub fn is_dynamic_or_kinematic(&self) -> bool {
679        self.body_type.is_dynamic_or_kinematic()
680    }
681
682    /// The offset index in the solver’s active set, or `u32::MAX` if
683    /// the rigid-body isn’t dynamic or kinematic.
684    // TODO: is this really necessary? Could we just always assign u32::MAX
685    //       to all the fixed bodies active set offsets?
686    pub fn effective_active_set_offset(&self) -> u32 {
687        if self.is_dynamic_or_kinematic() {
688            self.ids.active_set_id
689        } else {
690            u32::MAX
691        }
692    }
693
694    /// Checks if this is a fixed body (never moves, infinite mass).
695    ///
696    /// Fixed bodies are static geometry: walls, floors, terrain. They never move
697    /// and are not affected by any forces or collisions.
698    pub fn is_fixed(&self) -> bool {
699        self.body_type == RigidBodyType::Fixed
700    }
701
702    /// The mass of this rigid body in kilograms.
703    ///
704    /// Returns zero for fixed bodies (which technically have infinite mass).
705    /// Mass is computed from attached colliders' shapes and densities.
706    pub fn mass(&self) -> Real {
707        self.mprops.local_mprops.mass()
708    }
709
710    /// The predicted position of this rigid-body.
711    ///
712    /// If this rigid-body is kinematic this value is set by the `set_next_kinematic_position`
713    /// method and is used for estimating the kinematic body velocity at the next timestep.
714    /// For non-kinematic bodies, this value is currently unspecified.
715    pub fn next_position(&self) -> &Pose {
716        &self.pos.next_position
717    }
718
719    /// The gravity scale multiplier for this body.
720    ///
721    /// - `1.0` (default) = normal gravity
722    /// - `0.0` = no gravity (floating)
723    /// - `2.0` = double gravity (heavy/fast falling)
724    /// - Negative values = reverse gravity (objects fall upward!)
725    pub fn gravity_scale(&self) -> Real {
726        self.forces.gravity_scale
727    }
728
729    /// Sets how much gravity affects this body (multiplier).
730    ///
731    /// # Examples
732    /// ```
733    /// # use rapier3d::prelude::*;
734    /// # let mut bodies = RigidBodySet::new();
735    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
736    /// bodies[body].set_gravity_scale(0.0, true);  // Zero-G (space)
737    /// bodies[body].set_gravity_scale(0.1, true);  // Moon gravity
738    /// bodies[body].set_gravity_scale(2.0, true);  // Extra heavy
739    /// ```
740    pub fn set_gravity_scale(&mut self, scale: Real, wake_up: bool) {
741        if self.forces.gravity_scale != scale {
742            if wake_up && self.activation.sleeping {
743                self.changes.insert(RigidBodyChanges::SLEEP);
744                self.activation.sleeping = false;
745            }
746
747            self.forces.gravity_scale = scale;
748        }
749    }
750
751    /// The dominance group of this rigid-body.
752    pub fn dominance_group(&self) -> i8 {
753        self.dominance.0
754    }
755
756    /// The dominance group of this rigid-body.
757    pub fn set_dominance_group(&mut self, dominance: i8) {
758        if self.dominance.0 != dominance {
759            self.changes.insert(RigidBodyChanges::DOMINANCE);
760            self.dominance.0 = dominance
761        }
762    }
763
764    /// Adds a collider to this rigid-body.
765    pub(crate) fn add_collider_internal(
766        &mut self,
767        co_handle: ColliderHandle,
768        co_parent: &ColliderParent,
769        co_pos: &mut ColliderPosition,
770        co_shape: &ColliderShape,
771        co_mprops: &ColliderMassProps,
772    ) {
773        self.colliders.attach_collider(
774            self.body_type,
775            &mut self.changes,
776            &mut self.ccd,
777            &mut self.mprops,
778            &self.pos,
779            co_handle,
780            co_pos,
781            co_parent,
782            co_shape,
783            co_mprops,
784        )
785    }
786
787    /// Removes a collider from this rigid-body.
788    pub(crate) fn remove_collider_internal(&mut self, handle: ColliderHandle) {
789        if let Some(i) = self.colliders.0.iter().position(|e| *e == handle) {
790            self.changes.set(RigidBodyChanges::COLLIDERS, true);
791            self.colliders.0.swap_remove(i);
792        }
793    }
794
795    /// Forces this body to sleep immediately (stop simulating it).
796    ///
797    /// Sleeping bodies are excluded from physics simulation until disturbed. Use to manually
798    /// deactivate bodies you know won't move for a while.
799    ///
800    /// The body will auto-wake if:
801    /// - Hit by a moving object
802    /// - Connected via joint to a moving body
803    /// - Manually woken with `wake_up()`
804    pub fn sleep(&mut self) {
805        self.activation.sleep();
806        self.vels = RigidBodyVelocity::zero();
807    }
808
809    /// Wakes up this body if it's sleeping, making it active in the simulation.
810    ///
811    /// # Parameters
812    /// * `strong` - If `true`, guarantees the body stays awake for multiple frames.
813    ///   If `false`, it might sleep again immediately if conditions are met.
814    ///
815    /// Use after manually moving a sleeping body or to keep it active temporarily.
816    pub fn wake_up(&mut self, strong: bool) {
817        if self.activation.sleeping {
818            self.changes.insert(RigidBodyChanges::SLEEP);
819        }
820
821        self.activation.wake_up(strong);
822    }
823
824    /// Is this rigid body sleeping?
825    pub fn is_sleeping(&self) -> bool {
826        // TODO: should we:
827        // - return false for fixed bodies.
828        // - return true for non-sleeping dynamic bodies.
829        // - return true only for kinematic bodies with non-zero velocity?
830        self.activation.sleeping
831    }
832
833    /// Returns `true` if the body has non-zero linear or angular velocity.
834    ///
835    /// Useful for checking if an object is actually moving vs sitting still.
836    pub fn is_moving(&self) -> bool {
837        #[cfg(feature = "dim2")]
838        let angvel_is_nonzero = self.vels.angvel != 0.0;
839        #[cfg(feature = "dim3")]
840        let angvel_is_nonzero = self.vels.angvel != Default::default();
841        self.vels.linvel != Default::default() || angvel_is_nonzero
842    }
843
844    /// Returns both linear and angular velocity as a combined structure.
845    ///
846    /// Most users should use `linvel()` and `angvel()` separately instead.
847    pub fn vels(&self) -> &RigidBodyVelocity<Real> {
848        &self.vels
849    }
850
851    /// The current linear velocity (speed and direction of movement).
852    ///
853    /// This is how fast the body is moving in units per second. Use with [`set_linvel()`](Self::set_linvel)
854    /// to directly control the body's movement speed.
855    pub fn linvel(&self) -> Vector {
856        self.vels.linvel
857    }
858
859    /// The current angular velocity (rotation speed) in 2D.
860    ///
861    /// Returns radians per second. Positive = counter-clockwise, negative = clockwise.
862    #[cfg(feature = "dim2")]
863    pub fn angvel(&self) -> Real {
864        self.vels.angvel
865    }
866
867    /// The current angular velocity (rotation speed) in 3D.
868    ///
869    /// Returns a vector in radians per second around each axis (X, Y, Z).
870    #[cfg(feature = "dim3")]
871    pub fn angvel(&self) -> AngVector {
872        self.vels.angvel
873    }
874
875    /// Set both the angular and linear velocity of this rigid-body.
876    ///
877    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
878    /// put to sleep because it did not move for a while.
879    pub fn set_vels(&mut self, vels: RigidBodyVelocity<Real>, wake_up: bool) {
880        self.set_linvel(vels.linvel, wake_up);
881        #[cfg(feature = "dim2")]
882        self.set_angvel(vels.angvel, wake_up);
883        #[cfg(feature = "dim3")]
884        self.set_angvel(vels.angvel, wake_up);
885    }
886
887    /// Sets how fast this body is moving (linear velocity).
888    ///
889    /// This directly sets the body's velocity without applying forces. Use for:
890    /// - Player character movement
891    /// - Kinematic object control
892    /// - Instantly changing an object's speed
893    ///
894    /// For physics-based movement, consider using [`apply_impulse()`](Self::apply_impulse) or
895    /// [`add_force()`](Self::add_force) instead for more realistic behavior.
896    ///
897    /// # Example
898    /// ```
899    /// # use rapier3d::prelude::*;
900    /// # let mut bodies = RigidBodySet::new();
901    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
902    /// // Make the body move to the right at 5 units/second
903    /// bodies[body].set_linvel(Vector::new(5.0, 0.0, 0.0), true);
904    /// ```
905    pub fn set_linvel(&mut self, linvel: Vector, wake_up: bool) {
906        if self.vels.linvel != linvel {
907            match self.body_type {
908                RigidBodyType::Dynamic | RigidBodyType::KinematicVelocityBased => {
909                    self.vels.linvel = linvel;
910                    if wake_up {
911                        self.wake_up(true)
912                    }
913                }
914                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
915            }
916        }
917    }
918
919    /// The angular velocity of this rigid-body.
920    ///
921    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
922    /// put to sleep because it did not move for a while.
923    #[cfg(feature = "dim2")]
924    pub fn set_angvel(&mut self, angvel: Real, wake_up: bool) {
925        if self.vels.angvel != angvel {
926            match self.body_type {
927                RigidBodyType::Dynamic | RigidBodyType::KinematicVelocityBased => {
928                    self.vels.angvel = angvel;
929                    if wake_up {
930                        self.wake_up(true)
931                    }
932                }
933                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
934            }
935        }
936    }
937
938    /// The angular velocity of this rigid-body.
939    ///
940    /// If `wake_up` is `true` then the rigid-body will be woken up if it was
941    /// put to sleep because it did not move for a while.
942    #[cfg(feature = "dim3")]
943    pub fn set_angvel(&mut self, angvel: AngVector, wake_up: bool) {
944        if self.vels.angvel != angvel {
945            match self.body_type {
946                RigidBodyType::Dynamic | RigidBodyType::KinematicVelocityBased => {
947                    self.vels.angvel = angvel;
948                    if wake_up {
949                        self.wake_up(true)
950                    }
951                }
952                RigidBodyType::Fixed | RigidBodyType::KinematicPositionBased => {}
953            }
954        }
955    }
956
957    /// The current position (translation + rotation) of this rigid body in world space.
958    ///
959    /// Returns an `SimdPose` which combines both translation and rotation.
960    /// For just the position vector, use [`translation()`](Self::translation) instead.
961    #[inline]
962    pub fn position(&self) -> &Pose {
963        &self.pos.position
964    }
965
966    /// The current position vector of this rigid body (world coordinates).
967    ///
968    /// This is just the XYZ location, without rotation. For the full pose (position + rotation),
969    /// use [`position()`](Self::position).
970    #[inline]
971    pub fn translation(&self) -> Vector {
972        self.pos.position.translation
973    }
974
975    /// Teleports this rigid body to a new position (world coordinates).
976    ///
977    /// ⚠️ **Warning**: This instantly moves the body, ignoring physics! The body will "teleport"
978    /// without checking for collisions in between. Use this for:
979    /// - Respawning objects
980    /// - Level transitions
981    /// - Resetting positions
982    ///
983    /// For smooth physics-based movement, use velocities or forces instead.
984    ///
985    /// # Parameters
986    /// * `wake_up` - If `true`, prevents the body from immediately going back to sleep
987    #[inline]
988    pub fn set_translation(&mut self, translation: Vector, wake_up: bool) {
989        if self.pos.position.translation != translation
990            || self.pos.next_position.translation != translation
991        {
992            self.changes.insert(RigidBodyChanges::POSITION);
993            self.pos.position.translation = translation;
994            self.pos.next_position.translation = translation;
995
996            // Update the world mass-properties so torque application remains valid.
997            self.update_world_mass_properties();
998
999            // TODO: Do we really need to check that the body isn't dynamic?
1000            if wake_up && self.is_dynamic_or_kinematic() {
1001                self.wake_up(true)
1002            }
1003        }
1004    }
1005
1006    /// The current rotation/orientation of this rigid body.
1007    #[inline]
1008    pub fn rotation(&self) -> &Rotation {
1009        &self.pos.position.rotation
1010    }
1011
1012    /// Instantly rotates this rigid body to a new orientation.
1013    ///
1014    /// ⚠️ **Warning**: This teleports the rotation, ignoring physics! See [`set_translation()`](Self::set_translation) for details.
1015    #[inline]
1016    pub fn set_rotation(&mut self, rotation: Rotation, wake_up: bool) {
1017        if self.pos.position.rotation != rotation || self.pos.next_position.rotation != rotation {
1018            self.changes.insert(RigidBodyChanges::POSITION);
1019            self.pos.position.rotation = rotation;
1020            self.pos.next_position.rotation = rotation;
1021
1022            // Update the world mass-properties so torque application remains valid.
1023            self.update_world_mass_properties();
1024
1025            // TODO: Do we really need to check that the body isn't dynamic?
1026            if wake_up && self.is_dynamic_or_kinematic() {
1027                self.wake_up(true)
1028            }
1029        }
1030    }
1031
1032    /// Teleports this body to a new position and rotation (ignoring physics).
1033    ///
1034    /// ⚠️ **Warning**: Instantly moves the body without checking for collisions!
1035    /// For position-based kinematic bodies, this also resets their interpolated velocity to zero.
1036    ///
1037    /// Use for respawning, level transitions, or resetting positions.
1038    pub fn set_position(&mut self, pos: Pose, wake_up: bool) {
1039        if self.pos.position != pos || self.pos.next_position != pos {
1040            self.changes.insert(RigidBodyChanges::POSITION);
1041            self.pos.position = pos;
1042            self.pos.next_position = pos;
1043
1044            // Update the world mass-properties so torque application remains valid.
1045            self.update_world_mass_properties();
1046
1047            // TODO: Do we really need to check that the body isn't dynamic?
1048            if wake_up && self.is_dynamic_or_kinematic() {
1049                self.wake_up(true)
1050            }
1051        }
1052    }
1053
1054    /// For position-based kinematic bodies: sets where the body should rotate to by next frame.
1055    ///
1056    /// Only works for `KinematicPositionBased` bodies. Rapier computes the angular velocity
1057    /// needed to reach this rotation smoothly.
1058    pub fn set_next_kinematic_rotation(&mut self, rotation: Rotation) {
1059        if self.is_kinematic() {
1060            self.pos.next_position.rotation = rotation;
1061
1062            if self.pos.position.rotation != rotation {
1063                self.wake_up(true);
1064            }
1065        }
1066    }
1067
1068    /// For position-based kinematic bodies: sets where the body should move to by next frame.
1069    ///
1070    /// Only works for `KinematicPositionBased` bodies. Rapier computes the velocity
1071    /// needed to reach this position smoothly.
1072    pub fn set_next_kinematic_translation(&mut self, translation: Vector) {
1073        if self.is_kinematic() {
1074            self.pos.next_position.translation = translation;
1075
1076            if self.pos.position.translation != translation {
1077                self.wake_up(true);
1078            }
1079        }
1080    }
1081
1082    /// For position-based kinematic bodies: sets the target pose (position + rotation) for next frame.
1083    ///
1084    /// Only works for `KinematicPositionBased` bodies. Combines translation and rotation control.
1085    pub fn set_next_kinematic_position(&mut self, pos: Pose) {
1086        if self.is_kinematic() {
1087            self.pos.next_position = pos;
1088
1089            if self.pos.position != pos {
1090                self.wake_up(true);
1091            }
1092        }
1093    }
1094
1095    /// Predicts the next position of this rigid-body, by integrating its velocity and forces
1096    /// by a time of `dt`.
1097    pub(crate) fn predict_position_using_velocity_and_forces_with_max_dist(
1098        &self,
1099        dt: Real,
1100        max_dist: Real,
1101    ) -> Pose {
1102        let new_vels = self.forces.integrate(dt, &self.vels, &self.mprops);
1103        // Compute the clamped dt such that the body doesn't travel more than `max_dist`.
1104        let linvel_norm = new_vels.linvel.length();
1105        let clamped_linvel = linvel_norm.min(max_dist * crate::utils::inv(dt));
1106        let clamped_dt = dt * clamped_linvel * crate::utils::inv(linvel_norm);
1107        new_vels.integrate(
1108            clamped_dt,
1109            &self.pos.position,
1110            &self.mprops.local_mprops.local_com,
1111        )
1112    }
1113
1114    /// Calculates where this body will be after `dt` seconds, considering current velocity AND forces.
1115    ///
1116    /// Useful for predicting future positions or implementing custom integration.
1117    /// Accounts for gravity and applied forces.
1118    pub fn predict_position_using_velocity_and_forces(&self, dt: Real) -> Pose {
1119        self.pos
1120            .integrate_forces_and_velocities(dt, &self.forces, &self.vels, &self.mprops)
1121    }
1122
1123    /// Calculates where this body will be after `dt` seconds, considering only current velocity (not forces).
1124    ///
1125    /// Like `predict_position_using_velocity_and_forces()` but ignores applied forces.
1126    /// Useful when you only care about inertial motion without acceleration.
1127    pub fn predict_position_using_velocity(&self, dt: Real) -> Pose {
1128        self.vels
1129            .integrate(dt, &self.pos.position, &self.mprops.local_mprops.local_com)
1130    }
1131
1132    pub(crate) fn update_world_mass_properties(&mut self) {
1133        self.mprops
1134            .update_world_mass_properties(self.body_type, &self.pos.position);
1135    }
1136}
1137
1138/// ## Applying forces and torques
1139impl RigidBody {
1140    /// Clears all forces that were added with `add_force()`.
1141    ///
1142    /// User-defined forces are **not** cleared automatically: once added, a force keeps being
1143    /// applied at every physics step until you change it or clear it with this method. Call this
1144    /// when you want a previously-added force to stop being applied.
1145    pub fn reset_forces(&mut self, wake_up: bool) {
1146        if self.forces.user_force != Vector::ZERO {
1147            self.forces.user_force = Vector::ZERO;
1148
1149            if wake_up {
1150                self.wake_up(true);
1151            }
1152        }
1153    }
1154
1155    /// Clears all torques that were added with `add_torque()`.
1156    ///
1157    /// User-defined torques are **not** cleared automatically: once added, a torque keeps being
1158    /// applied at every physics step until you change it or clear it with this method.
1159    #[cfg(feature = "dim2")]
1160    pub fn reset_torques(&mut self, wake_up: bool) {
1161        if self.forces.user_torque != 0.0 {
1162            self.forces.user_torque = 0.0;
1163
1164            if wake_up {
1165                self.wake_up(true);
1166            }
1167        }
1168    }
1169
1170    /// Clears all torques that were added with `add_torque()`.
1171    ///
1172    /// User-defined torques are **not** cleared automatically: once added, a torque keeps being
1173    /// applied at every physics step until you change it or clear it with this method.
1174    #[cfg(feature = "dim3")]
1175    pub fn reset_torques(&mut self, wake_up: bool) {
1176        if self.forces.user_torque != AngVector::ZERO {
1177            self.forces.user_torque = AngVector::ZERO;
1178
1179            if wake_up {
1180                self.wake_up(true);
1181            }
1182        }
1183    }
1184
1185    /// Applies a continuous force to this body (like thrust, wind, or magnets).
1186    ///
1187    /// Unlike [`apply_impulse()`](Self::apply_impulse) which is instant, a force is applied
1188    /// continuously over time. Successive calls to `add_force()` accumulate. Use for:
1189    /// - Rocket/jet thrust
1190    /// - Wind or water currents
1191    /// - Magnetic/gravity fields
1192    /// - Continuous pushing/pulling
1193    ///
1194    /// User-defined forces are **not** cleared automatically: once added, a force keeps being
1195    /// applied at every physics step until you change it or clear it with
1196    /// [`reset_forces()`](Self::reset_forces). To apply a force for a single step only, call
1197    /// `reset_forces()` after stepping the simulation.
1198    ///
1199    /// # Example
1200    /// ```
1201    /// # use rapier3d::prelude::*;
1202    /// # let mut bodies = RigidBodySet::new();
1203    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
1204    /// // Apply thrust every frame
1205    /// bodies[body].add_force(Vector::new(0.0, 100.0, 0.0), true);
1206    /// ```
1207    ///
1208    /// Only affects dynamic bodies (does nothing for kinematic/fixed bodies).
1209    pub fn add_force(&mut self, force: Vector, wake_up: bool) {
1210        if force != Vector::ZERO && self.body_type == RigidBodyType::Dynamic {
1211            self.forces.user_force += force;
1212
1213            if wake_up {
1214                self.wake_up(true);
1215            }
1216        }
1217    }
1218
1219    /// Applies a continuous rotational force (torque) to spin this body.
1220    ///
1221    /// Like `add_force()` but for rotation. Successive calls accumulate, and the torque is **not**
1222    /// cleared automatically (see [`reset_torques()`](Self::reset_torques)).
1223    /// In 2D: positive = counter-clockwise, negative = clockwise.
1224    ///
1225    /// Only affects dynamic bodies.
1226    #[cfg(feature = "dim2")]
1227    pub fn add_torque(&mut self, torque: Real, wake_up: bool) {
1228        if !torque.is_zero() && self.body_type == RigidBodyType::Dynamic {
1229            self.forces.user_torque += torque;
1230
1231            if wake_up {
1232                self.wake_up(true);
1233            }
1234        }
1235    }
1236
1237    /// Applies a continuous rotational force (torque) to spin this body.
1238    ///
1239    /// Like `add_force()` but for rotation. In 3D, the torque vector direction
1240    /// determines the rotation axis (right-hand rule).
1241    ///
1242    /// Only affects dynamic bodies.
1243    #[cfg(feature = "dim3")]
1244    pub fn add_torque(&mut self, torque: Vector, wake_up: bool) {
1245        if torque != Vector::ZERO && self.body_type == RigidBodyType::Dynamic {
1246            self.forces.user_torque += torque;
1247
1248            if wake_up {
1249                self.wake_up(true);
1250            }
1251        }
1252    }
1253
1254    /// Applies force at a specific point on the body (creates both force and torque).
1255    ///
1256    /// When you push an object off-center, it both moves AND spins. This method handles both effects.
1257    /// The force creates linear acceleration, and the offset from center-of-mass creates torque.
1258    ///
1259    /// Use for: Forces applied at contact points, explosions at specific locations, pushing objects.
1260    ///
1261    /// # Parameters
1262    /// * `force` - The force vector to apply
1263    /// * `point` - Where to apply the force (world coordinates)
1264    ///
1265    /// Only affects dynamic bodies.
1266    pub fn add_force_at_point(&mut self, force: Vector, point: Vector, wake_up: bool) {
1267        if force != Vector::ZERO && self.body_type == RigidBodyType::Dynamic {
1268            self.forces.user_force += force;
1269            self.forces.user_torque += (point - self.mprops.world_com).gcross(force);
1270
1271            if wake_up {
1272                self.wake_up(true);
1273            }
1274        }
1275    }
1276}
1277
1278/// ## Applying impulses and angular impulses
1279impl RigidBody {
1280    /// Instantly changes the velocity by applying an impulse (like a kick or explosion).
1281    ///
1282    /// An impulse is an instant change in momentum. Think of it as a "one-time push" that
1283    /// immediately affects velocity. Use for:
1284    /// - Jumping (apply upward impulse)
1285    /// - Explosions pushing objects away
1286    /// - Getting hit by something
1287    /// - Launching projectiles
1288    ///
1289    /// The effect depends on the body's mass - heavier objects will be affected less by the same impulse.
1290    ///
1291    /// **For continuous forces** (like rocket thrust or wind), use [`add_force()`](Self::add_force) instead.
1292    ///
1293    /// # Example
1294    /// ```
1295    /// # use rapier3d::prelude::*;
1296    /// # let mut bodies = RigidBodySet::new();
1297    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
1298    /// // Make a character jump
1299    /// bodies[body].apply_impulse(Vector::new(0.0, 300.0, 0.0), true);
1300    /// ```
1301    ///
1302    /// Only affects dynamic bodies (does nothing for kinematic/fixed bodies).
1303    #[profiling::function]
1304    pub fn apply_impulse(&mut self, impulse: Vector, wake_up: bool) {
1305        if impulse != Vector::ZERO && self.body_type == RigidBodyType::Dynamic {
1306            self.vels.linvel += impulse * self.mprops.effective_inv_mass;
1307
1308            if wake_up {
1309                self.wake_up(true);
1310            }
1311        }
1312    }
1313
1314    /// Applies an angular impulse at the center-of-mass of this rigid-body.
1315    /// The impulse is applied right away, changing the angular velocity.
1316    /// This does nothing on non-dynamic bodies.
1317    #[cfg(feature = "dim2")]
1318    #[profiling::function]
1319    pub fn apply_torque_impulse(&mut self, torque_impulse: Real, wake_up: bool) {
1320        if !torque_impulse.is_zero() && self.body_type == RigidBodyType::Dynamic {
1321            self.vels.angvel += self.mprops.effective_world_inv_inertia * torque_impulse;
1322
1323            if wake_up {
1324                self.wake_up(true);
1325            }
1326        }
1327    }
1328
1329    /// Instantly changes rotation speed by applying angular impulse (like a sudden spin).
1330    ///
1331    /// In 3D, the impulse vector direction determines the spin axis (right-hand rule).
1332    /// Like `apply_impulse()` but for rotation. Only affects dynamic bodies.
1333    #[cfg(feature = "dim3")]
1334    #[profiling::function]
1335    pub fn apply_torque_impulse(&mut self, torque_impulse: Vector, wake_up: bool) {
1336        if torque_impulse != Vector::ZERO && self.body_type == RigidBodyType::Dynamic {
1337            self.vels.angvel += self.mprops.effective_world_inv_inertia * torque_impulse;
1338
1339            if wake_up {
1340                self.wake_up(true);
1341            }
1342        }
1343    }
1344
1345    /// Applies impulse at a specific point on the body (creates both linear and angular effects).
1346    ///
1347    /// Like `add_force_at_point()` but instant instead of continuous. When you hit an object
1348    /// off-center, it both flies away AND spins - this method handles both.
1349    ///
1350    /// # Example
1351    /// ```
1352    /// # use rapier3d::prelude::*;
1353    /// # let mut bodies = RigidBodySet::new();
1354    /// # let body = bodies.insert(RigidBodyBuilder::dynamic());
1355    /// // Hit the top-left corner of a box
1356    /// bodies[body].apply_impulse_at_point(
1357    ///     Vector::new(100.0, 0.0, 0.0),
1358    ///     Vector::new(-0.5, 0.5, 0.0),  // Top-left of a 1x1 box
1359    ///     true
1360    /// );
1361    /// // Box will move right AND spin
1362    /// ```
1363    ///
1364    /// Only affects dynamic bodies.
1365    pub fn apply_impulse_at_point(&mut self, impulse: Vector, point: Vector, wake_up: bool) {
1366        let torque_impulse = (point - self.mprops.world_com).gcross(impulse);
1367        self.apply_impulse(impulse, wake_up);
1368        self.apply_torque_impulse(torque_impulse, wake_up);
1369    }
1370
1371    /// Returns the total force currently queued to be applied this frame.
1372    ///
1373    /// This is the sum of all `add_force()` calls since the last physics step.
1374    /// Returns zero for non-dynamic bodies.
1375    pub fn user_force(&self) -> Vector {
1376        if self.body_type == RigidBodyType::Dynamic {
1377            self.forces.user_force
1378        } else {
1379            Vector::ZERO
1380        }
1381    }
1382
1383    /// Returns the total torque currently queued to be applied this frame.
1384    ///
1385    /// This is the sum of all `add_torque()` calls since the last physics step.
1386    /// Returns zero for non-dynamic bodies.
1387    pub fn user_torque(&self) -> AngVector {
1388        if self.body_type == RigidBodyType::Dynamic {
1389            self.forces.user_torque
1390        } else {
1391            #[cfg(feature = "dim2")]
1392            {
1393                0.0
1394            }
1395            #[cfg(feature = "dim3")]
1396            {
1397                AngVector::ZERO
1398            }
1399        }
1400    }
1401
1402    /// Checks if gyroscopic forces are enabled (3D only).
1403    ///
1404    /// Gyroscopic forces cause spinning objects to resist changes in rotation axis
1405    /// (like how spinning tops stay upright). Adds slight CPU cost.
1406    #[cfg(feature = "dim3")]
1407    pub fn gyroscopic_forces_enabled(&self) -> bool {
1408        self.forces.gyroscopic_forces_enabled
1409    }
1410
1411    /// Enables/disables gyroscopic forces for more realistic spinning behavior.
1412    ///
1413    /// When enabled, rapidly spinning objects resist rotation axis changes (like gyroscopes).
1414    /// Examples: spinning tops, flywheels, rotating spacecraft.
1415    ///
1416    /// **Default**: Disabled (costs performance, rarely needed in games).
1417    #[cfg(feature = "dim3")]
1418    pub fn enable_gyroscopic_forces(&mut self, enabled: bool) {
1419        self.forces.gyroscopic_forces_enabled = enabled;
1420    }
1421}
1422
1423impl RigidBody {
1424    /// Calculates the velocity at a specific point on this body.
1425    ///
1426    /// Due to rotation, different points on a rigid body move at different speeds.
1427    /// This computes the linear velocity at any world-space point.
1428    ///
1429    /// Useful for: impact calculations, particle effects, sound volume based on impact speed.
1430    pub fn velocity_at_point(&self, point: Vector) -> Vector {
1431        self.vels.velocity_at_point(point, self.mprops.world_com)
1432    }
1433
1434    /// Calculates the kinetic energy of this body (energy from motion).
1435    ///
1436    /// Returns `0.5 * mass * velocity² + 0.5 * inertia * angular_velocity²`
1437    /// Useful for physics-based gameplay (energy tracking, damage based on impact energy).
1438    pub fn kinetic_energy(&self) -> Real {
1439        self.vels.kinetic_energy(&self.mprops)
1440    }
1441
1442    /// Calculates the gravitational potential energy of this body.
1443    ///
1444    /// Returns `mass * gravity * height`. Useful for energy conservation checks.
1445    pub fn gravitational_potential_energy(&self, dt: Real, gravity: Vector) -> Real {
1446        let world_com = self.mprops.local_mprops.world_com(&self.pos.position);
1447
1448        // Project position back along velocity vector one half-step (leap-frog)
1449        // to sync up the potential energy with the kinetic energy:
1450        let world_com = world_com - self.vels.linvel * (dt / 2.0);
1451
1452        -self.mass() * self.forces.gravity_scale * gravity.dot(world_com)
1453    }
1454
1455    /// Computes the angular velocity of this rigid-body after application of gyroscopic forces.
1456    #[cfg(feature = "dim3")]
1457    pub fn angvel_with_gyroscopic_forces(&self, dt: Real) -> AngVector {
1458        let mprops = &self.mprops.local_mprops;
1459        // World-space principal axes = body rotation ∘ principal frame.
1460        let principal_axes = self.pos.position.rotation * mprops.principal_inertia_local_frame;
1461        gyroscopic_corrected_angvel(
1462            self.angvel(),
1463            principal_axes,
1464            mprops.principal_inertia(),
1465            mprops.inv_principal_inertia,
1466            dt,
1467        )
1468    }
1469}
1470
1471/// A builder for creating rigid bodies with custom properties.
1472///
1473/// This builder lets you configure all properties of a rigid body before adding it to your world.
1474/// Start with one of the type constructors ([`dynamic()`](Self::dynamic), [`fixed()`](Self::fixed),
1475///  [`kinematic_position_based()`](Self::kinematic_position_based), or
1476/// [`kinematic_velocity_based()`](Self::kinematic_velocity_based)), then chain property setters,
1477/// and finally call [`build()`](Self::build).
1478///
1479/// # Example
1480///
1481/// ```
1482/// # use rapier3d::prelude::*;
1483/// let body = RigidBodyBuilder::dynamic()
1484///     .translation(Vector::new(0.0, 5.0, 0.0))  // Start 5 units above ground
1485///     .linvel(Vector::new(1.0, 0.0, 0.0))       // Initial velocity to the right
1486///     .can_sleep(false)                          // Keep always active
1487///     .build();
1488/// ```
1489#[derive(Clone, Debug, PartialEq)]
1490#[must_use = "Builder functions return the updated builder"]
1491pub struct RigidBodyBuilder {
1492    /// The initial position of the rigid-body to be built.
1493    pub position: Pose,
1494    /// The linear velocity of the rigid-body to be built.
1495    pub linvel: Vector,
1496    /// The angular velocity of the rigid-body to be built.
1497    pub angvel: AngVector,
1498    /// The scale factor applied to the gravity affecting the rigid-body to be built, `1.0` by default.
1499    pub gravity_scale: Real,
1500    /// Damping factor for gradually slowing down the translational motion of the rigid-body, `0.0` by default.
1501    pub linear_damping: Real,
1502    /// Damping factor for gradually slowing down the angular motion of the rigid-body, `0.0` by default.
1503    pub angular_damping: Real,
1504    /// The type of rigid-body being constructed.
1505    pub body_type: RigidBodyType,
1506    mprops_flags: LockedAxes,
1507    /// The additional mass-properties of the rigid-body being built. See [`RigidBodyBuilder::additional_mass_properties`] for more information.
1508    additional_mass_properties: RigidBodyAdditionalMassProps,
1509    /// Whether the rigid-body to be created can sleep if it reaches a dynamic equilibrium.
1510    pub can_sleep: bool,
1511    /// Whether the rigid-body is to be created asleep.
1512    pub sleeping: bool,
1513    /// Whether full ("bullet") Continuous Collision-Detection is enabled for the rigid-body to be
1514    /// built. Fast dynamic bodies always sweep fixed colliders; this also sweeps kinematic and
1515    /// dynamic bodies. CCD prevents tunneling but may allow limited interpenetration of colliders.
1516    pub ccd_enabled: bool,
1517    /// The maximum prediction distance Soft Continuous Collision-Detection.
1518    ///
1519    /// When set to 0, soft CCD is disabled. Soft-CCD helps prevent tunneling especially of
1520    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
1521    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
1522    /// performance badly by increasing the work needed from the broad-phase.
1523    ///
1524    /// It is a generally cheaper variant of regular CCD (that can be enabled with
1525    /// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
1526    /// shape-cast and substeps.
1527    pub soft_ccd_prediction: Real,
1528    /// Allow the rigid-body being built to exceed the angular speed cap.
1529    /// See [`RigidBody::set_allow_fast_rotation`].
1530    pub allow_fast_rotation: bool,
1531    /// The dominance group of the rigid-body to be built.
1532    pub dominance_group: i8,
1533    /// Will the rigid-body being built be enabled?
1534    pub enabled: bool,
1535    /// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
1536    pub user_data: u128,
1537    /// The additional number of solver iterations run for the constraints directly
1538    /// involving this rigid-body.
1539    ///
1540    /// See [`RigidBody::set_additional_solver_iterations`] for additional information.
1541    pub additional_solver_iterations: usize,
1542    /// Are gyroscopic forces enabled for this rigid-body?
1543    pub gyroscopic_forces_enabled: bool,
1544}
1545
1546impl Default for RigidBodyBuilder {
1547    fn default() -> Self {
1548        Self::dynamic()
1549    }
1550}
1551
1552impl RigidBodyBuilder {
1553    /// Initialize a new builder for a rigid body which is either fixed, dynamic, or kinematic.
1554    pub fn new(body_type: RigidBodyType) -> Self {
1555        #[cfg(feature = "dim2")]
1556        let angvel = 0.0;
1557        #[cfg(feature = "dim3")]
1558        let angvel = AngVector::ZERO;
1559
1560        Self {
1561            position: Pose::IDENTITY,
1562            linvel: Vector::ZERO,
1563            angvel,
1564            gravity_scale: 1.0,
1565            linear_damping: 0.0,
1566            angular_damping: 0.0,
1567            body_type,
1568            mprops_flags: LockedAxes::empty(),
1569            additional_mass_properties: RigidBodyAdditionalMassProps::default(),
1570            can_sleep: true,
1571            sleeping: false,
1572            ccd_enabled: false,
1573            soft_ccd_prediction: 0.0,
1574            allow_fast_rotation: false,
1575            dominance_group: 0,
1576            enabled: true,
1577            user_data: 0,
1578            additional_solver_iterations: 0,
1579            gyroscopic_forces_enabled: true,
1580        }
1581    }
1582
1583    /// Initializes the builder of a new fixed rigid body.
1584    #[deprecated(note = "use `RigidBodyBuilder::fixed()` instead")]
1585    pub fn new_static() -> Self {
1586        Self::fixed()
1587    }
1588    /// Initializes the builder of a new velocity-based kinematic rigid body.
1589    #[deprecated(note = "use `RigidBodyBuilder::kinematic_velocity_based()` instead")]
1590    pub fn new_kinematic_velocity_based() -> Self {
1591        Self::kinematic_velocity_based()
1592    }
1593    /// Initializes the builder of a new position-based kinematic rigid body.
1594    #[deprecated(note = "use `RigidBodyBuilder::kinematic_position_based()` instead")]
1595    pub fn new_kinematic_position_based() -> Self {
1596        Self::kinematic_position_based()
1597    }
1598
1599    /// Creates a builder for a **fixed** (static) rigid body.
1600    ///
1601    /// Fixed bodies never move and are not affected by any forces. Use them for:
1602    /// - Walls, floors, and ceilings
1603    /// - Static terrain and level geometry
1604    /// - Any object that should never move in your simulation
1605    ///
1606    /// Fixed bodies have infinite mass and never sleep.
1607    pub fn fixed() -> Self {
1608        Self::new(RigidBodyType::Fixed)
1609    }
1610
1611    /// Creates a builder for a **velocity-based kinematic** rigid body.
1612    ///
1613    /// Kinematic bodies are moved by directly setting their velocity (not by applying forces).
1614    /// They can push dynamic bodies but are not affected by them. Use for:
1615    /// - Moving platforms and elevators
1616    /// - Doors and sliding panels
1617    /// - Any object you want to control directly while still affecting other physics objects
1618    ///
1619    /// Set velocity with [`RigidBody::set_linvel`] and [`RigidBody::set_angvel`].
1620    pub fn kinematic_velocity_based() -> Self {
1621        Self::new(RigidBodyType::KinematicVelocityBased)
1622    }
1623
1624    /// Creates a builder for a **position-based kinematic** rigid body.
1625    ///
1626    /// Similar to velocity-based kinematic, but you control it by setting its next position
1627    /// directly rather than setting velocity. Rapier will automatically compute the velocity
1628    /// needed to reach that position. Use for objects animated by external systems.
1629    pub fn kinematic_position_based() -> Self {
1630        Self::new(RigidBodyType::KinematicPositionBased)
1631    }
1632
1633    /// Creates a builder for a **dynamic** rigid body.
1634    ///
1635    /// Dynamic bodies are fully simulated - they respond to gravity, forces, collisions, and
1636    /// constraints. This is the most common type for interactive objects. Use for:
1637    /// - Physics objects that should fall and bounce (boxes, spheres, ragdolls)
1638    /// - Projectiles and debris
1639    /// - Vehicles and moving characters (when not using kinematic control)
1640    /// - Any object that should behave realistically under physics
1641    ///
1642    /// Dynamic bodies can sleep (become inactive) when at rest to save performance.
1643    pub fn dynamic() -> Self {
1644        Self::new(RigidBodyType::Dynamic)
1645    }
1646
1647    /// Sets the additional number of solver iterations run for the constraints directly
1648    /// involving this rigid-body.
1649    ///
1650    /// See [`RigidBody::set_additional_solver_iterations`] for additional information.
1651    pub fn additional_solver_iterations(mut self, additional_iterations: usize) -> Self {
1652        self.additional_solver_iterations = additional_iterations;
1653        self
1654    }
1655
1656    /// Sets the scale applied to the gravity force affecting the rigid-body to be created.
1657    pub fn gravity_scale(mut self, scale_factor: Real) -> Self {
1658        self.gravity_scale = scale_factor;
1659        self
1660    }
1661
1662    /// Sets the dominance group (advanced collision priority system).
1663    ///
1664    /// Higher dominance groups can push lower ones but not vice versa.
1665    /// Rarely needed - most games don't use this. Default is 0 (all equal priority).
1666    ///
1667    /// Use case: Heavy objects that should always push lighter ones in contacts.
1668    pub fn dominance_group(mut self, group: i8) -> Self {
1669        self.dominance_group = group;
1670        self
1671    }
1672
1673    /// Sets the initial position (XYZ coordinates) where this body will be created.
1674    ///
1675    /// # Example
1676    /// ```
1677    /// # use rapier3d::prelude::*;
1678    /// let body = RigidBodyBuilder::dynamic()
1679    ///     .translation(Vector::new(10.0, 5.0, -3.0))
1680    ///     .build();
1681    /// ```
1682    pub fn translation(mut self, translation: Vector) -> Self {
1683        self.position.translation = translation;
1684        self
1685    }
1686
1687    /// Sets the initial rotation/orientation of the body to be created.
1688    ///
1689    /// # Example
1690    /// ```
1691    /// # use rapier3d::prelude::*;
1692    /// // Rotate 45 degrees around Y axis (in 3D)
1693    /// let body = RigidBodyBuilder::dynamic()
1694    ///     .rotation(Vector::new(0.0, std::f32::consts::PI / 4.0, 0.0))
1695    ///     .build();
1696    /// ```
1697    pub fn rotation(mut self, angle: AngVector) -> Self {
1698        self.position.rotation = rotation_from_angle(angle);
1699        self
1700    }
1701
1702    /// Sets the initial position (translation and orientation) of the rigid-body to be created.
1703    #[deprecated = "renamed to `RigidBodyBuilder::pose`"]
1704    pub fn position(mut self, pos: Pose) -> Self {
1705        self.position = pos;
1706        self
1707    }
1708
1709    /// Sets the initial pose (translation and orientation) of the rigid-body to be created.
1710    pub fn pose(mut self, pos: Pose) -> Self {
1711        self.position = pos;
1712        self
1713    }
1714
1715    /// An arbitrary user-defined 128-bit integer associated to the rigid-bodies built by this builder.
1716    pub fn user_data(mut self, data: u128) -> Self {
1717        self.user_data = data;
1718        self
1719    }
1720
1721    /// Sets the additional mass-properties of the rigid-body being built.
1722    ///
1723    /// This will be overridden by a call to [`Self::additional_mass`] so it only makes sense to call
1724    /// either [`Self::additional_mass`] or [`Self::additional_mass_properties`].    
1725    ///
1726    /// Note that "additional" means that the final mass-properties of the rigid-bodies depends
1727    /// on the initial mass-properties of the rigid-body (set by this method)
1728    /// to which is added the contributions of all the colliders with non-zero density
1729    /// attached to this rigid-body.
1730    ///
1731    /// Therefore, if you want your provided mass-properties to be the final
1732    /// mass-properties of your rigid-body, don't attach colliders to it, or
1733    /// only attach colliders with densities equal to zero.
1734    pub fn additional_mass_properties(mut self, mprops: MassProperties) -> Self {
1735        self.additional_mass_properties = RigidBodyAdditionalMassProps::MassProps(mprops);
1736        self
1737    }
1738
1739    /// Sets the additional mass of the rigid-body being built.
1740    ///
1741    /// This will be overridden by a call to [`Self::additional_mass_properties`] so it only makes
1742    /// sense to call either [`Self::additional_mass`] or [`Self::additional_mass_properties`].    
1743    ///
1744    /// This is only the "additional" mass because the total mass of the  rigid-body is
1745    /// equal to the sum of this additional mass and the mass computed from the colliders
1746    /// (with non-zero densities) attached to this rigid-body.
1747    ///
1748    /// The total angular inertia of the rigid-body will be scaled automatically based on this
1749    /// additional mass. If this scaling effect isn’t desired, use [`Self::additional_mass_properties`]
1750    /// instead of this method.
1751    ///
1752    /// # Parameters
1753    /// * `mass`- The mass that will be added to the created rigid-body.
1754    pub fn additional_mass(mut self, mass: Real) -> Self {
1755        self.additional_mass_properties = RigidBodyAdditionalMassProps::Mass(mass);
1756        self
1757    }
1758
1759    /// Sets which movement axes are locked (cannot move/rotate).
1760    ///
1761    /// See [`LockedAxes`] for examples of constraining movement to specific directions.
1762    pub fn locked_axes(mut self, locked_axes: LockedAxes) -> Self {
1763        self.mprops_flags = locked_axes;
1764        self
1765    }
1766
1767    /// Prevents all translational movement (body can still rotate).
1768    ///
1769    /// Use for turrets, spinning objects fixed in place, etc.
1770    pub fn lock_translations(mut self) -> Self {
1771        self.mprops_flags.set(LockedAxes::TRANSLATION_LOCKED, true);
1772        self
1773    }
1774
1775    /// Locks translation along specific axes.
1776    ///
1777    /// # Example
1778    /// ```
1779    /// # use rapier3d::prelude::*;
1780    /// // 2D game in 3D: lock Z movement
1781    /// let body = RigidBodyBuilder::dynamic()
1782    ///     .enabled_translations(true, true, false)  // X, Y free; Z locked
1783    ///     .build();
1784    /// ```
1785    pub fn enabled_translations(
1786        mut self,
1787        allow_translations_x: bool,
1788        allow_translations_y: bool,
1789        #[cfg(feature = "dim3")] allow_translations_z: bool,
1790    ) -> Self {
1791        self.mprops_flags
1792            .set(LockedAxes::TRANSLATION_LOCKED_X, !allow_translations_x);
1793        self.mprops_flags
1794            .set(LockedAxes::TRANSLATION_LOCKED_Y, !allow_translations_y);
1795        #[cfg(feature = "dim3")]
1796        self.mprops_flags
1797            .set(LockedAxes::TRANSLATION_LOCKED_Z, !allow_translations_z);
1798        self
1799    }
1800
1801    #[deprecated(note = "Use `enabled_translations` instead")]
1802    /// Only allow translations of this rigid-body around specific coordinate axes.
1803    pub fn restrict_translations(
1804        self,
1805        allow_translations_x: bool,
1806        allow_translations_y: bool,
1807        #[cfg(feature = "dim3")] allow_translations_z: bool,
1808    ) -> Self {
1809        self.enabled_translations(
1810            allow_translations_x,
1811            allow_translations_y,
1812            #[cfg(feature = "dim3")]
1813            allow_translations_z,
1814        )
1815    }
1816
1817    /// Prevents all rotational movement (body can still translate).
1818    ///
1819    /// Use for characters that shouldn't tip over, objects that should only slide, etc.
1820    pub fn lock_rotations(mut self) -> Self {
1821        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_X, true);
1822        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_Y, true);
1823        self.mprops_flags.set(LockedAxes::ROTATION_LOCKED_Z, true);
1824        self
1825    }
1826
1827    /// Only allow rotations of this rigid-body around specific coordinate axes.
1828    #[cfg(feature = "dim3")]
1829    pub fn enabled_rotations(
1830        mut self,
1831        allow_rotations_x: bool,
1832        allow_rotations_y: bool,
1833        allow_rotations_z: bool,
1834    ) -> Self {
1835        self.mprops_flags
1836            .set(LockedAxes::ROTATION_LOCKED_X, !allow_rotations_x);
1837        self.mprops_flags
1838            .set(LockedAxes::ROTATION_LOCKED_Y, !allow_rotations_y);
1839        self.mprops_flags
1840            .set(LockedAxes::ROTATION_LOCKED_Z, !allow_rotations_z);
1841        self
1842    }
1843
1844    /// Locks or unlocks rotations of this rigid-body along each cartesian axes.
1845    #[deprecated(note = "Use `enabled_rotations` instead")]
1846    #[cfg(feature = "dim3")]
1847    pub fn restrict_rotations(
1848        self,
1849        allow_rotations_x: bool,
1850        allow_rotations_y: bool,
1851        allow_rotations_z: bool,
1852    ) -> Self {
1853        self.enabled_rotations(allow_rotations_x, allow_rotations_y, allow_rotations_z)
1854    }
1855
1856    /// Sets linear damping (how quickly linear velocity decreases over time).
1857    ///
1858    /// Models air resistance, drag, etc. Higher values = faster slowdown.
1859    /// - `0.0` = no drag (space)
1860    /// - `0.1` = light drag (air)
1861    /// - `1.0+` = heavy drag (underwater)
1862    pub fn linear_damping(mut self, factor: Real) -> Self {
1863        self.linear_damping = factor;
1864        self
1865    }
1866
1867    /// Sets angular damping (how quickly rotation speed decreases over time).
1868    ///
1869    /// Models rotational drag. Higher values = spinning stops faster.
1870    pub fn angular_damping(mut self, factor: Real) -> Self {
1871        self.angular_damping = factor;
1872        self
1873    }
1874
1875    /// Sets the initial linear velocity (movement speed and direction).
1876    ///
1877    /// The body will start moving at this velocity when created.
1878    pub fn linvel(mut self, linvel: Vector) -> Self {
1879        self.linvel = linvel;
1880        self
1881    }
1882
1883    /// Sets the initial angular velocity (rotation speed).
1884    ///
1885    /// The body will start rotating at this speed when created.
1886    pub fn angvel(mut self, angvel: AngVector) -> Self {
1887        self.angvel = angvel;
1888        self
1889    }
1890
1891    /// Sets whether this body can go to sleep when at rest (default: `true`).
1892    ///
1893    /// Sleeping bodies are excluded from simulation until disturbed, saving CPU.
1894    /// Set to `false` if you need the body always active (e.g., for continuous queries).
1895    pub fn can_sleep(mut self, can_sleep: bool) -> Self {
1896        self.can_sleep = can_sleep;
1897        self
1898    }
1899
1900    /// Enables full ("bullet") Continuous Collision Detection: fast dynamic bodies already sweep
1901    /// **fixed** colliders automatically; this upgrades the body to also sweep **kinematic and
1902    /// dynamic** bodies at extra cost — for projectiles and fast small
1903    /// objects that must not tunnel through other moving bodies. Setting
1904    /// [`IntegrationParameters::max_ccd_substeps`] to `0` disables CCD world-wide.
1905    ///
1906    /// # Example
1907    /// ```
1908    /// # use rapier3d::prelude::*;
1909    /// // Bullet that should never tunnel through walls or other moving bodies
1910    /// let bullet = RigidBodyBuilder::dynamic()
1911    ///     .ccd_enabled(true)
1912    ///     .build();
1913    /// ```
1914    pub fn ccd_enabled(mut self, enabled: bool) -> Self {
1915        self.ccd_enabled = enabled;
1916        self
1917    }
1918
1919    /// Sets the maximum prediction distance Soft Continuous Collision-Detection.
1920    ///
1921    /// When set to 0, soft-CCD is disabled. Soft-CCD helps prevent tunneling especially of
1922    /// slow-but-thin to moderately fast objects. The soft CCD prediction distance indicates how
1923    /// far in the object’s path the CCD algorithm is allowed to inspect. Large values can impact
1924    /// performance badly by increasing the work needed from the broad-phase.
1925    ///
1926    /// It is a generally cheaper variant of regular CCD (that can be enabled with
1927    /// [`RigidBodyBuilder::ccd_enabled`] since it relies on predictive constraints instead of
1928    /// shape-cast and substeps.
1929    pub fn soft_ccd_prediction(mut self, prediction_distance: Real) -> Self {
1930        self.soft_ccd_prediction = prediction_distance;
1931        self
1932    }
1933
1934    /// Allow the rigid-body being built to exceed the angular speed cap.
1935    ///
1936    /// By default angular velocity is clamped each substep to ~45°/step to keep CCD reliable;
1937    /// pass `true` for bodies that must spin fast, e.g. wheels.
1938    pub fn allow_fast_rotation(mut self, allow: bool) -> Self {
1939        self.allow_fast_rotation = allow;
1940        self
1941    }
1942
1943    /// Sets whether the rigid-body is to be created asleep.
1944    pub fn sleeping(mut self, sleeping: bool) -> Self {
1945        self.sleeping = sleeping;
1946        self
1947    }
1948
1949    /// Are gyroscopic forces enabled for this rigid-body?
1950    ///
1951    /// Enabling gyroscopic forces allows more realistic behaviors like gyroscopic precession,
1952    /// but result in a slight performance overhead.
1953    ///
1954    /// Disabled by default.
1955    #[cfg(feature = "dim3")]
1956    pub fn gyroscopic_forces_enabled(mut self, enabled: bool) -> Self {
1957        self.gyroscopic_forces_enabled = enabled;
1958        self
1959    }
1960
1961    /// Enable or disable the rigid-body after its creation.
1962    pub fn enabled(mut self, enabled: bool) -> Self {
1963        self.enabled = enabled;
1964        self
1965    }
1966
1967    /// Build a new rigid-body with the parameters configured with this builder.
1968    pub fn build(&self) -> RigidBody {
1969        let mut rb = RigidBody::new();
1970        rb.pos.next_position = self.position;
1971        rb.pos.position = self.position;
1972        rb.vels.linvel = self.linvel;
1973        rb.vels.angvel = self.angvel;
1974        rb.body_type = self.body_type;
1975        rb.user_data = self.user_data;
1976        rb.additional_solver_iterations = self.additional_solver_iterations;
1977
1978        if self.additional_mass_properties
1979            != RigidBodyAdditionalMassProps::MassProps(MassProperties::default())
1980            && self.additional_mass_properties != RigidBodyAdditionalMassProps::Mass(0.0)
1981        {
1982            rb.mprops.additional_local_mprops = Some(Box::new(self.additional_mass_properties));
1983        }
1984
1985        rb.mprops.flags = self.mprops_flags;
1986        rb.damping.linear_damping = self.linear_damping;
1987        rb.damping.angular_damping = self.angular_damping;
1988        rb.forces.gravity_scale = self.gravity_scale;
1989        #[cfg(feature = "dim3")]
1990        {
1991            rb.forces.gyroscopic_forces_enabled = self.gyroscopic_forces_enabled;
1992        }
1993        rb.dominance = RigidBodyDominance(self.dominance_group);
1994        rb.enabled = self.enabled;
1995        rb.enable_ccd(self.ccd_enabled);
1996        rb.set_soft_ccd_prediction(self.soft_ccd_prediction);
1997        rb.set_allow_fast_rotation(self.allow_fast_rotation);
1998
1999        if self.can_sleep && self.sleeping {
2000            rb.sleep();
2001        }
2002
2003        if !self.can_sleep {
2004            rb.activation.normalized_linear_threshold = -1.0;
2005            rb.activation.angular_threshold = -1.0;
2006        }
2007
2008        rb
2009    }
2010}
2011
2012impl From<RigidBodyBuilder> for RigidBody {
2013    fn from(val: RigidBodyBuilder) -> RigidBody {
2014        val.build()
2015    }
2016}
2017
2018/// One explicit, angular-momentum-preserving gyroscopic correction of a world-space angular velocity,
2019/// computed in the world principal-inertia frame (`principal_axes`) so `w × I·w` is exact for tilted
2020/// axes. Shared by [`RigidBody::angvel_with_gyroscopic_forces`] and the solver's per-substep pass.
2021#[cfg(feature = "dim3")]
2022#[inline]
2023pub(crate) fn gyroscopic_corrected_angvel(
2024    angvel: AngVector,
2025    principal_axes: Rotation,
2026    principal_inertia: AngVector,
2027    inv_principal_inertia: AngVector,
2028    dt: Real,
2029) -> AngVector {
2030    // NOTE: integrating the gyroscopic forces implicitly are both slower and
2031    //       very dissipative. Instead, we only keep the explicit term and
2032    //       ensure angular momentum is preserved (similar to Jolt).
2033    let w = principal_axes.inverse() * angvel;
2034    let curr_momentum = principal_inertia * w;
2035    let explicit_gyro_momentum = -w.cross(curr_momentum) * dt;
2036    let total_momentum = curr_momentum + explicit_gyro_momentum;
2037    let total_momentum_sqnorm = total_momentum.length_squared();
2038
2039    if total_momentum_sqnorm != 0.0 {
2040        let capped_momentum =
2041            total_momentum * (curr_momentum.length_squared() / total_momentum_sqnorm).sqrt();
2042        principal_axes * (inv_principal_inertia * capped_momentum)
2043    } else {
2044        angvel
2045    }
2046}