rapier3d/dynamics/
rigid_body.rs

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