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}