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