avian3d/dynamics/rigid_body/forces/query_data.rs
1use crate::{dynamics::integrator::VelocityIntegrationData, prelude::*};
2use bevy::ecs::{
3 query::{Has, QueryData},
4 system::lifetimeless::{Read, Write},
5};
6
7use super::AccumulatedLocalAcceleration;
8
9/// A helper [`QueryData`] for applying forces, impulses, and accelerations to dynamic [rigid bodies](RigidBody).
10///
11/// For constant forces that persist across time steps, consider using components like [`ConstantForce`] instead.
12///
13/// See the [module-level documentation](crate::dynamics::rigid_body::forces) for more general information about forces in Avian.
14///
15/// # Usage
16///
17/// To use [`Forces`], add it to a [`Query`](bevy::prelude::Query) (without `&` or `&mut`),
18/// and use the associated methods to apply forces, impulses, and accelerations to the rigid bodies.
19///
20/// ```
21#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
22#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
23/// # use bevy::prelude::*;
24/// #
25/// # #[cfg(feature = "f32")]
26/// fn apply_forces(mut query: Query<Forces>) {
27/// for mut forces in &mut query {
28/// // Apply a force of 10 N in the positive Y direction to the entity.
29#[cfg_attr(
30 feature = "2d",
31 doc = " forces.apply_force(Vec2::new(0.0, 10.0));"
32)]
33#[cfg_attr(
34 feature = "3d",
35 doc = " forces.apply_force(Vec3::new(0.0, 10.0, 0.0));"
36)]
37/// }
38/// }
39/// ```
40///
41/// The force is applied continuously during the physics step, and cleared automatically after the step is complete.
42///
43/// By default, applying forces to [sleeping](Sleeping) bodies will wake them up. If this is not desired,
44/// the [`non_waking`](ForcesItem::non_waking) method can be used to fetch a [`NonWakingForcesItem`]
45/// that allows applying forces to a body without waking it up.
46///
47/// ```
48#[cfg_attr(feature = "2d", doc = "# use avian2d::{math::Vector, prelude::*};")]
49#[cfg_attr(feature = "3d", doc = "# use avian3d::{math::Vector, prelude::*};")]
50/// # use bevy::prelude::*;
51/// #
52/// # fn apply_impulses(mut query: Query<Forces>) {
53/// # for mut forces in &mut query {
54/// # let force = Vector::default();
55/// // Apply a force without waking up the body if it is sleeping.
56/// forces.non_waking().apply_force(force);
57/// # }
58/// # }
59/// ```
60///
61/// [`Forces`] can also apply forces and impulses at a specific point in the world. If the point is not aligned
62/// with the [center of mass](CenterOfMass), it will apply a torque to the body.
63///
64/// ```
65#[cfg_attr(feature = "2d", doc = "# use avian2d::{math::Vector, prelude::*};")]
66#[cfg_attr(feature = "3d", doc = "# use avian3d::{math::Vector, prelude::*};")]
67/// # use bevy::prelude::*;
68/// #
69/// # fn apply_impulses(mut query: Query<Forces>) {
70/// # for mut forces in &mut query {
71/// # let force = Vector::default();
72/// # let point = Vector::default();
73/// // Apply an impulse at a specific point in the world.
74/// // Unlike forces, impulses are applied immediately to the velocity.
75/// forces.apply_linear_impulse_at_point(force, point);
76/// # }
77/// # }
78/// ```
79///
80/// As an example, you could implement radial gravity that pulls rigid bodies towards the world origin
81/// with a system like the following:
82///
83/// ```
84#[cfg_attr(feature = "2d", doc = "# use avian2d::prelude::*;")]
85#[cfg_attr(feature = "3d", doc = "# use avian3d::prelude::*;")]
86/// # use bevy::prelude::*;
87/// #
88/// # #[cfg(feature = "f32")]
89/// fn radial_gravity(mut query: Query<(Forces, &GlobalTransform)>) {
90/// for (mut forces, global_transform) in &mut query {
91/// // Compute the direction towards the center of the world.
92/// let direction = -global_transform.translation().normalize_or_zero();
93/// // Apply a linear acceleration of 9.81 m/s² towards the center of the world.
94#[cfg_attr(
95 feature = "2d",
96 doc = " forces.apply_linear_acceleration(direction.truncate() * 9.81);"
97)]
98#[cfg_attr(
99 feature = "3d",
100 doc = " forces.apply_linear_acceleration(direction * 9.81);"
101)]
102/// }
103/// }
104/// ```
105#[derive(QueryData)]
106#[query_data(mutable)]
107pub struct Forces {
108 position: Read<Position>,
109 rotation: Read<Rotation>,
110 linear_velocity: Write<LinearVelocity>,
111 angular_velocity: Write<AngularVelocity>,
112 mass: Read<ComputedMass>,
113 angular_inertia: Read<ComputedAngularInertia>,
114 center_of_mass: Read<ComputedCenterOfMass>,
115 locked_axes: Option<Read<LockedAxes>>,
116 integration: Write<VelocityIntegrationData>,
117 accumulated_local_acceleration: Write<AccumulatedLocalAcceleration>,
118 sleep_timer: Option<Write<SleepTimer>>,
119 is_sleeping: Has<Sleeping>,
120}
121
122/// A [`ForcesItem`] that does not wake up the body when applying forces, torques, impulses, or accelerations.
123/// Returned by [`ForcesItem::non_waking`].
124///
125/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
126pub struct NonWakingForcesItem<'w, 's>(pub ForcesItem<'w, 's>);
127
128impl ForcesItem<'_, '_> {
129 /// Reborrows `self` as a new instance of [`ForcesItem`].
130 #[inline]
131 #[must_use]
132 pub fn reborrow(&mut self) -> ForcesItem<'_, '_> {
133 ForcesItem {
134 position: self.position,
135 rotation: self.rotation,
136 linear_velocity: self.linear_velocity.reborrow(),
137 angular_velocity: self.angular_velocity.reborrow(),
138 mass: self.mass,
139 angular_inertia: self.angular_inertia,
140 center_of_mass: self.center_of_mass,
141 locked_axes: self.locked_axes,
142 integration: self.integration.reborrow(),
143 accumulated_local_acceleration: self.accumulated_local_acceleration.reborrow(),
144 sleep_timer: self.sleep_timer.as_mut().map(|s| s.reborrow()),
145 is_sleeping: self.is_sleeping,
146 }
147 }
148
149 /// Returns a [`NonWakingForcesItem`] that allows applying forces, impulses, and accelerations
150 /// without waking up the body if it is sleeping.
151 #[inline]
152 #[must_use]
153 pub fn non_waking(&mut self) -> NonWakingForcesItem<'_, '_> {
154 NonWakingForcesItem(self.reborrow())
155 }
156}
157
158impl<'w, 's> NonWakingForcesItem<'w, 's> {
159 /// Returns a [`ForcesItem`] that will wake up the body when applying forces, impulses, or accelerations.
160 #[inline]
161 #[must_use]
162 pub fn waking(self) -> ForcesItem<'w, 's> {
163 self.0
164 }
165}
166
167impl ReadRigidBodyForces for ForcesItem<'_, '_> {}
168impl ReadRigidBodyForces for NonWakingForcesItem<'_, '_> {}
169impl ReadRigidBodyForces for ForcesReadOnlyItem<'_, '_> {}
170impl WriteRigidBodyForces for ForcesItem<'_, '_> {}
171impl WriteRigidBodyForces for NonWakingForcesItem<'_, '_> {}
172
173/// A trait for reading and writing forces of a dynamic [rigid body](RigidBody).
174///
175/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
176/// returned by [`Forces`].
177///
178/// See the documentation of [`Forces`] for more information on how to work with forces in Avian.
179pub trait RigidBodyForces: ReadRigidBodyForces + WriteRigidBodyForces {}
180
181/// A trait for reading forces of a dynamic [rigid body](RigidBody).
182///
183/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
184/// returned by [`Forces`].
185///
186/// See the documentation of [`Forces`] for more information on how to work with forces in Avian.
187#[expect(
188 private_bounds,
189 reason = "The internal methods should not be publicly accessible."
190)]
191pub trait ReadRigidBodyForces: ReadRigidBodyForcesInternal {
192 /// Returns the [`Position`] of the body.
193 #[inline]
194 fn position(&self) -> &Position {
195 self.pos()
196 }
197
198 /// Returns the [`Rotation`] of the body.
199 #[inline]
200 fn rotation(&self) -> &Rotation {
201 self.rot()
202 }
203
204 /// Returns the [`LinearVelocity`] of the body in world space.
205 #[inline]
206 fn linear_velocity(&self) -> Vector {
207 self.lin_vel()
208 }
209
210 /// Returns the [`AngularVelocity`] of the body in world space.
211 #[inline]
212 fn angular_velocity(&self) -> AngularVector {
213 self.ang_vel()
214 }
215
216 /// Returns the linear acceleration that the body has accumulated
217 /// before the physics step in world space, including acceleration
218 /// caused by forces.
219 ///
220 /// This does not include gravity, contact forces, or joint forces.
221 /// Only forces and accelerations applied through [`Forces`] are included.
222 #[inline]
223 fn accumulated_linear_acceleration(&self) -> Vector {
224 // The linear increment is treated as linear acceleration until the integration step.
225 let world_linear_acceleration = self.integration_data().linear_increment;
226 let local_linear_acceleration = self.accumulated_local_acceleration().linear;
227
228 // Return the total world-space linear acceleration.
229 self.locked_axes()
230 .apply_to_vec(world_linear_acceleration + self.rot() * local_linear_acceleration)
231 }
232
233 /// Returns the angular acceleration that the body has accumulated
234 /// before the physics step in world space, including acceleration
235 /// caused by torques.
236 ///
237 /// This does not include gravity, contact forces, or joint forces.
238 /// Only torques and accelerations applied through [`Forces`] are included.
239 #[cfg(feature = "2d")]
240 #[inline]
241 fn accumulated_angular_acceleration(&self) -> AngularVector {
242 // The angular increment is treated as angular acceleration until the integration step.
243 self.locked_axes()
244 .apply_to_angular_velocity(self.integration_data().angular_increment)
245 }
246
247 /// Returns the angular acceleration that the body has accumulated
248 /// before the physics step in world space, including acceleration
249 /// caused by torques.
250 ///
251 /// This does not include gravity, contact forces, or joint forces.
252 /// Only torques and accelerations applied through [`Forces`] are included.
253 #[cfg(feature = "3d")]
254 #[inline]
255 fn accumulated_angular_acceleration(&self) -> AngularVector {
256 // The angular increment is treated as angular acceleration until the integration step.
257 let world_angular_acceleration = self.integration_data().angular_increment;
258 let local_angular_acceleration = self.accumulated_local_acceleration().angular;
259
260 // Return the total world-space angular acceleration.
261 self.locked_axes().apply_to_angular_velocity(
262 world_angular_acceleration + self.rot() * local_angular_acceleration,
263 )
264 }
265
266 /// Returns the velocity of a point in world space on the body.
267 #[inline]
268 #[doc(alias = "linear_velocity_at_point")]
269 fn velocity_at_point(&self, world_point: Vector) -> Vector {
270 let offset = world_point - self.global_center_of_mass();
271 #[cfg(feature = "2d")]
272 {
273 self.linear_velocity() + self.angular_velocity() * offset.perp()
274 }
275 #[cfg(feature = "3d")]
276 {
277 self.linear_velocity() + self.angular_velocity().cross(offset)
278 }
279 }
280}
281
282/// A trait for applying forces, impulses, and accelerations to a dynamic [rigid body](RigidBody).
283///
284/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
285/// returned by [`Forces`].
286///
287/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
288#[expect(
289 private_bounds,
290 reason = "The internal methods should not be publicly accessible."
291)]
292pub trait WriteRigidBodyForces: ReadRigidBodyForces + WriteRigidBodyForcesInternal {
293 /// Applies a force at the center of mass in world space. The unit is typically N or kg⋅m/s².
294 ///
295 /// The force is applied continuously over the physics step and cleared afterwards.
296 ///
297 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
298 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
299 #[inline]
300 fn apply_force(&mut self, force: Vector) {
301 if force != Vector::ZERO && self.try_wake_up() {
302 let acceleration = self.inverse_mass() * force;
303 self.integration_data_mut()
304 .apply_linear_acceleration(acceleration);
305 }
306 }
307
308 /// Applies a force at the given point in world space. The unit is typically N or kg⋅m/s².
309 ///
310 /// If the point is not at the center of mass, the force will also generate a torque.
311 ///
312 /// The force is applied continuously over the physics step and cleared afterwards.
313 ///
314 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
315 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
316 ///
317 /// # Note
318 ///
319 /// If the [`Transform`] of the body is modified before applying the force,
320 /// the torque will be computed using an outdated global center of mass.
321 /// This may cause problems when applying a force right after teleporting
322 /// an entity, as the torque could grow very large if the distance between the point
323 /// and old center of mass is large.
324 ///
325 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
326 /// to update the global physics transform after modifying [`Transform`].
327 ///
328 /// [`Transform`]: bevy::transform::components::Transform
329 #[inline]
330 fn apply_force_at_point(&mut self, force: Vector, world_point: Vector) {
331 // Note: This does not consider the rotation of the body during substeps,
332 // so the torque may not be accurate if the body is rotating quickly.
333 self.apply_force(force);
334 self.apply_torque(cross(world_point - self.global_center_of_mass(), force));
335 }
336
337 /// Applies a force at the center of mass in local space. The unit is typically N or kg⋅m/s².
338 ///
339 /// The force is applied continuously over the physics step and cleared afterwards.
340 ///
341 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
342 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
343 #[inline]
344 fn apply_local_force(&mut self, force: Vector) {
345 if force != Vector::ZERO && self.try_wake_up() {
346 let acceleration = self.inverse_mass() * force;
347 self.accumulated_local_acceleration_mut().linear += acceleration;
348 }
349 }
350
351 /// Applies a torque in world space. The unit is typically N⋅m or kg⋅m²/s².
352 ///
353 /// The torque is applied continuously over the physics step and cleared afterwards.
354 ///
355 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
356 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
357 #[inline]
358 fn apply_torque(&mut self, torque: AngularVector) {
359 if torque != AngularVector::ZERO && self.try_wake_up() {
360 let acceleration = self.effective_inverse_angular_inertia() * torque;
361 self.integration_data_mut()
362 .apply_angular_acceleration(acceleration);
363 }
364 }
365
366 /// Applies a torque in local space. The unit is typically N⋅m or kg⋅m²/s².
367 ///
368 /// The torque is applied continuously over the physics step and cleared afterwards.
369 ///
370 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
371 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
372 #[cfg(feature = "3d")]
373 #[inline]
374 fn apply_local_torque(&mut self, torque: AngularVector) {
375 if torque != AngularVector::ZERO && self.try_wake_up() {
376 let acceleration = self.inverse_angular_inertia() * torque;
377 self.accumulated_local_acceleration_mut().angular += acceleration;
378 }
379 }
380
381 /// Applies a linear impulse at the center of mass in world space. The unit is typically N⋅s or kg⋅m/s.
382 ///
383 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
384 ///
385 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
386 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
387 #[inline]
388 fn apply_linear_impulse(&mut self, impulse: Vector) {
389 if impulse != Vector::ZERO && self.try_wake_up() {
390 let effective_inverse_mass = self
391 .locked_axes()
392 .apply_to_vec(Vector::splat(self.inverse_mass()));
393 let delta_vel = effective_inverse_mass * impulse;
394 *self.linear_velocity_mut() += delta_vel;
395 }
396 }
397
398 /// Applies a linear impulse at the given point in world space. The unit is typically N⋅s or kg⋅m/s.
399 ///
400 /// If the point is not at the center of mass, the impulse will also generate an angular impulse.
401 ///
402 /// The impulse modifies the [`LinearVelocity`] and [`AngularVelocity`] of the body immediately.
403 ///
404 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
405 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
406 ///
407 /// # Note
408 ///
409 /// If the [`Transform`] of the body is modified before applying the impulse,
410 /// the torque will be computed using an outdated global center of mass.
411 /// This may cause problems when applying a impulse right after teleporting
412 /// an entity, as the torque could grow very large if the distance between the point
413 /// and old center of mass is large.
414 ///
415 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
416 /// to update the global physics transform after modifying [`Transform`].
417 ///
418 /// [`Transform`]: bevy::transform::components::Transform
419 #[inline]
420 fn apply_linear_impulse_at_point(&mut self, impulse: Vector, world_point: Vector) {
421 self.apply_linear_impulse(impulse);
422 self.apply_angular_impulse(cross(world_point - self.global_center_of_mass(), impulse));
423 }
424
425 /// Applies a linear impulse in local space. The unit is typically N⋅s or kg⋅m/s.
426 ///
427 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
428 ///
429 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
430 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
431 #[inline]
432 fn apply_local_linear_impulse(&mut self, impulse: Vector) {
433 if impulse != Vector::ZERO && self.try_wake_up() {
434 let world_impulse = self.rot() * impulse;
435 let effective_inverse_mass = self
436 .locked_axes()
437 .apply_to_vec(Vector::splat(self.inverse_mass()));
438 let delta_vel = effective_inverse_mass * world_impulse;
439 *self.linear_velocity_mut() += delta_vel;
440 }
441 }
442
443 /// Applies an angular impulse in world space. The unit is typically N⋅m⋅s or kg⋅m²/s.
444 ///
445 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
446 ///
447 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
448 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
449 #[inline]
450 fn apply_angular_impulse(&mut self, impulse: AngularVector) {
451 if impulse != AngularVector::ZERO && self.try_wake_up() {
452 let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
453 let delta_vel = effective_inverse_angular_inertia * impulse;
454 *self.angular_velocity_mut() += delta_vel;
455 }
456 }
457
458 /// Applies an angular impulse in local space. The unit is typically N⋅m⋅s or kg⋅m²/s.
459 ///
460 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
461 ///
462 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
463 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
464 #[cfg(feature = "3d")]
465 #[inline]
466 fn apply_local_angular_impulse(&mut self, impulse: AngularVector) {
467 if impulse != AngularVector::ZERO && self.try_wake_up() {
468 let world_impulse = self.rot() * impulse;
469 let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
470 let delta_vel = effective_inverse_angular_inertia * world_impulse;
471 *self.angular_velocity_mut() += delta_vel;
472 }
473 }
474
475 /// Applies a linear acceleration, ignoring mass. The unit is typically m/s².
476 ///
477 /// The acceleration is applied continuously over the physics step and cleared afterwards.
478 ///
479 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
480 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
481 #[inline]
482 fn apply_linear_acceleration(&mut self, acceleration: Vector) {
483 if acceleration != Vector::ZERO && self.try_wake_up() {
484 self.integration_data_mut()
485 .apply_linear_acceleration(acceleration);
486 }
487 }
488
489 /// Applies a linear acceleration at the given point in world space. The unit is typically m/s².
490 ///
491 /// If the point is not at the center of mass, the acceleration will also generate an angular acceleration.
492 ///
493 /// The acceleration is applied continuously over the physics step and cleared afterwards.
494 ///
495 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
496 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
497 ///
498 /// # Note
499 ///
500 /// If the [`Transform`] of the body is modified before applying the acceleration,
501 /// the angular acceleration will be computed using an outdated global center of mass.
502 /// This may cause problems when applying a acceleration right after teleporting
503 /// an entity, as the angular acceleration could grow very large if the distance between the point
504 /// and old center of mass is large.
505 ///
506 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
507 /// to update the global physics transform after modifying [`Transform`].
508 ///
509 /// [`Transform`]: bevy::transform::components::Transform
510 #[inline]
511 fn apply_linear_acceleration_at_point(&mut self, acceleration: Vector, world_point: Vector) {
512 self.apply_linear_acceleration(acceleration);
513 self.apply_angular_acceleration(cross(
514 world_point - self.global_center_of_mass(),
515 acceleration,
516 ));
517 }
518
519 /// Applies a linear acceleration in local space, ignoring mass. The unit is typically m/s².
520 ///
521 /// The acceleration is applied continuously over the physics step and cleared afterwards.
522 ///
523 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
524 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
525 #[inline]
526 fn apply_local_linear_acceleration(&mut self, acceleration: Vector) {
527 if acceleration != Vector::ZERO && self.try_wake_up() {
528 self.accumulated_local_acceleration_mut().linear += acceleration;
529 }
530 }
531
532 /// Applies an angular acceleration, ignoring angular inertia. The unit is rad/s².
533 ///
534 /// The acceleration is applied continuously over the physics step and cleared afterwards.
535 ///
536 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
537 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
538 #[inline]
539 fn apply_angular_acceleration(&mut self, acceleration: AngularVector) {
540 if acceleration != AngularVector::ZERO && self.try_wake_up() {
541 self.integration_data_mut()
542 .apply_angular_acceleration(acceleration);
543 }
544 }
545
546 /// Applies an angular acceleration in local space, ignoring angular inertia. The unit is rad/s².
547 ///
548 /// The acceleration is applied continuously over the physics step and cleared afterwards.
549 ///
550 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
551 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
552 #[cfg(feature = "3d")]
553 #[inline]
554 fn apply_local_angular_acceleration(&mut self, acceleration: AngularVector) {
555 if acceleration != AngularVector::ZERO && self.try_wake_up() {
556 self.accumulated_local_acceleration_mut().angular += acceleration;
557 }
558 }
559
560 /// Returns a mutable reference to the [`LinearVelocity`] of the body in world space.
561 #[inline]
562 fn linear_velocity_mut(&mut self) -> &mut Vector {
563 self.lin_vel_mut()
564 }
565
566 /// Returns a mutable reference to the [`AngularVelocity`] of the body in world space.
567 #[inline]
568 fn angular_velocity_mut(&mut self) -> &mut AngularVector {
569 self.ang_vel_mut()
570 }
571
572 /// Resets the accumulated linear acceleration to zero.
573 #[inline]
574 fn reset_accumulated_linear_acceleration(&mut self) {
575 self.integration_data_mut().linear_increment = Vector::ZERO;
576 self.accumulated_local_acceleration_mut().linear = Vector::ZERO;
577 }
578
579 /// Resets the accumulated angular acceleration to zero.
580 #[inline]
581 fn reset_accumulated_angular_acceleration(&mut self) {
582 self.integration_data_mut().angular_increment = AngularVector::ZERO;
583 #[cfg(feature = "3d")]
584 {
585 self.accumulated_local_acceleration_mut().angular = AngularVector::ZERO;
586 }
587 }
588}
589
590/// A trait to provide internal read-only getters for [`ReadRigidBodyForces`].
591trait ReadRigidBodyForcesInternal {
592 fn pos(&self) -> &Position;
593 fn rot(&self) -> &Rotation;
594 fn lin_vel(&self) -> Vector;
595 fn ang_vel(&self) -> AngularVector;
596 fn global_center_of_mass(&self) -> Vector;
597 fn locked_axes(&self) -> LockedAxes;
598 fn integration_data(&self) -> &VelocityIntegrationData;
599 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration;
600}
601
602/// A trait to provide internal mutable getters and helpers for [`WriteRigidBodyForces`].
603trait WriteRigidBodyForcesInternal: ReadRigidBodyForcesInternal {
604 fn lin_vel_mut(&mut self) -> &mut Vector;
605 fn ang_vel_mut(&mut self) -> &mut AngularVector;
606 fn inverse_mass(&self) -> Scalar;
607 #[cfg(feature = "3d")]
608 fn inverse_angular_inertia(&self) -> SymmetricTensor;
609 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor;
610 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData;
611 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration;
612 fn try_wake_up(&mut self) -> bool;
613}
614
615impl ReadRigidBodyForcesInternal for ForcesItem<'_, '_> {
616 #[inline]
617 fn pos(&self) -> &Position {
618 self.position
619 }
620 #[inline]
621 fn rot(&self) -> &Rotation {
622 self.rotation
623 }
624 #[inline]
625 fn lin_vel(&self) -> Vector {
626 self.linear_velocity.0
627 }
628 #[inline]
629 fn ang_vel(&self) -> AngularVector {
630 self.angular_velocity.0
631 }
632 #[inline]
633 fn global_center_of_mass(&self) -> Vector {
634 self.position.0 + self.rotation * self.center_of_mass.0
635 }
636 #[inline]
637 fn locked_axes(&self) -> LockedAxes {
638 self.locked_axes.copied().unwrap_or_default()
639 }
640 #[inline]
641 fn integration_data(&self) -> &VelocityIntegrationData {
642 &self.integration
643 }
644 #[inline]
645 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
646 &self.accumulated_local_acceleration
647 }
648}
649
650impl WriteRigidBodyForcesInternal for ForcesItem<'_, '_> {
651 #[inline]
652 fn lin_vel_mut(&mut self) -> &mut Vector {
653 &mut self.linear_velocity.0
654 }
655 #[inline]
656 fn ang_vel_mut(&mut self) -> &mut AngularVector {
657 &mut self.angular_velocity.0
658 }
659 #[inline]
660 fn inverse_mass(&self) -> Scalar {
661 self.mass.inverse()
662 }
663 #[inline]
664 #[cfg(feature = "3d")]
665 fn inverse_angular_inertia(&self) -> SymmetricTensor {
666 self.angular_inertia.inverse()
667 }
668 #[inline]
669 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
670 #[cfg(feature = "2d")]
671 let global_angular_inertia = *self.angular_inertia;
672 #[cfg(feature = "3d")]
673 let global_angular_inertia = self.angular_inertia.rotated(self.rotation.0);
674 self.locked_axes()
675 .apply_to_angular_inertia(global_angular_inertia)
676 .inverse()
677 }
678 #[inline]
679 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
680 &mut self.integration
681 }
682 #[inline]
683 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
684 &mut self.accumulated_local_acceleration
685 }
686 #[inline]
687 fn try_wake_up(&mut self) -> bool {
688 // Wake up the body. Return `true` to indicate that the body is awake.
689 if let Some(sleep_timer) = &mut self.sleep_timer {
690 sleep_timer.0 = 0.0;
691 }
692 true
693 }
694}
695
696impl ReadRigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
697 #[inline]
698 fn pos(&self) -> &Position {
699 self.0.position()
700 }
701 #[inline]
702 fn rot(&self) -> &Rotation {
703 self.0.rot()
704 }
705 #[inline]
706 fn lin_vel(&self) -> Vector {
707 self.0.lin_vel()
708 }
709 #[inline]
710 fn ang_vel(&self) -> AngularVector {
711 self.0.ang_vel()
712 }
713 #[inline]
714 fn global_center_of_mass(&self) -> Vector {
715 self.0.global_center_of_mass()
716 }
717 #[inline]
718 fn locked_axes(&self) -> LockedAxes {
719 self.0.locked_axes()
720 }
721 #[inline]
722 fn integration_data(&self) -> &VelocityIntegrationData {
723 self.0.integration_data()
724 }
725 #[inline]
726 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
727 self.0.accumulated_local_acceleration()
728 }
729}
730
731impl ReadRigidBodyForcesInternal for ForcesReadOnlyItem<'_, '_> {
732 #[inline]
733 fn pos(&self) -> &Position {
734 self.position
735 }
736 #[inline]
737 fn rot(&self) -> &Rotation {
738 self.rotation
739 }
740 #[inline]
741 fn lin_vel(&self) -> Vector {
742 self.linear_velocity.0
743 }
744 #[inline]
745 fn ang_vel(&self) -> AngularVector {
746 self.angular_velocity.0
747 }
748 #[inline]
749 fn global_center_of_mass(&self) -> Vector {
750 self.position.0 + self.rotation * self.center_of_mass.0
751 }
752 #[inline]
753 fn locked_axes(&self) -> LockedAxes {
754 self.locked_axes.copied().unwrap_or_default()
755 }
756 #[inline]
757 fn integration_data(&self) -> &VelocityIntegrationData {
758 self.integration
759 }
760 #[inline]
761 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
762 self.accumulated_local_acceleration
763 }
764}
765
766impl WriteRigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
767 #[inline]
768 fn lin_vel_mut(&mut self) -> &mut Vector {
769 self.0.lin_vel_mut()
770 }
771 #[inline]
772 fn ang_vel_mut(&mut self) -> &mut AngularVector {
773 self.0.ang_vel_mut()
774 }
775 #[inline]
776 fn inverse_mass(&self) -> Scalar {
777 self.0.inverse_mass()
778 }
779 #[inline]
780 #[cfg(feature = "3d")]
781 fn inverse_angular_inertia(&self) -> SymmetricTensor {
782 self.0.inverse_angular_inertia()
783 }
784 #[inline]
785 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
786 self.0.effective_inverse_angular_inertia()
787 }
788 #[inline]
789 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
790 self.0.integration_data_mut()
791 }
792 #[inline]
793 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
794 self.0.accumulated_local_acceleration_mut()
795 }
796 #[inline]
797 fn try_wake_up(&mut self) -> bool {
798 // Don't wake up the body.
799 // Return `true` if the body is already awake and forces should be applied.
800 !self.0.is_sleeping
801 }
802}