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}