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