avian2d/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 RigidBodyForces for ForcesItem<'_, '_> {}
168impl RigidBodyForces for NonWakingForcesItem<'_, '_> {}
169
170/// A trait for applying forces, impulses, and accelerations to a dynamic [rigid body](RigidBody).
171///
172/// This is implemented as a shared interface for the [`ForcesItem`] and [`NonWakingForcesItem`]
173/// returned by [`Forces`].
174///
175/// See the documentation of [`Forces`] for more information on how to apply forces in Avian.
176#[expect(
177 private_bounds,
178 reason = "The `data` method should not be publicly accessible."
179)]
180pub trait RigidBodyForces: RigidBodyForcesInternal {
181 /// Applies a force at the center of mass in world space. The unit is typically N or kg⋅m/s².
182 ///
183 /// The force is applied continuously over the physics step and cleared afterwards.
184 ///
185 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
186 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
187 #[inline]
188 fn apply_force(&mut self, force: Vector) {
189 if force != Vector::ZERO && self.try_wake_up() {
190 let acceleration = self.inverse_mass() * force;
191 self.integration_data_mut()
192 .apply_linear_acceleration(acceleration);
193 }
194 }
195
196 /// Applies a force at the given point in world space. The unit is typically N or kg⋅m/s².
197 ///
198 /// If the point is not at the center of mass, the force will also generate a torque.
199 ///
200 /// The force is applied continuously over the physics step and cleared afterwards.
201 ///
202 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
203 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
204 ///
205 /// # Note
206 ///
207 /// If the [`Transform`] of the body is modified before applying the force,
208 /// the torque will be computed using an outdated global center of mass.
209 /// This may cause problems when applying a force right after teleporting
210 /// an entity, as the torque could grow very large if the distance between the point
211 /// and old center of mass is large.
212 ///
213 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
214 /// to update the global physics transform after modifying [`Transform`].
215 ///
216 /// [`Transform`]: bevy::transform::components::Transform
217 #[inline]
218 fn apply_force_at_point(&mut self, force: Vector, world_point: Vector) {
219 // Note: This does not consider the rotation of the body during substeps,
220 // so the torque may not be accurate if the body is rotating quickly.
221 self.apply_force(force);
222 self.apply_torque(cross(world_point - self.global_center_of_mass(), force));
223 }
224
225 /// Applies a force at the center of mass in local space. The unit is typically N or kg⋅m/s².
226 ///
227 /// The force is applied continuously over the physics step and cleared afterwards.
228 ///
229 /// By default, a non-zero force will wake up the body if it is sleeping. This can be prevented
230 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
231 #[inline]
232 fn apply_local_force(&mut self, force: Vector) {
233 if force != Vector::ZERO && self.try_wake_up() {
234 let acceleration = self.inverse_mass() * force;
235 self.accumulated_local_acceleration_mut().linear += acceleration;
236 }
237 }
238
239 /// Applies a torque in world space. The unit is typically N⋅m or kg⋅m²/s².
240 ///
241 /// The torque is applied continuously over the physics step and cleared afterwards.
242 ///
243 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
244 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
245 #[inline]
246 fn apply_torque(&mut self, torque: AngularVector) {
247 if torque != AngularVector::ZERO && self.try_wake_up() {
248 let acceleration = self.effective_inverse_angular_inertia() * torque;
249 self.integration_data_mut()
250 .apply_angular_acceleration(acceleration);
251 }
252 }
253
254 /// Applies a torque in local space. The unit is typically N⋅m or kg⋅m²/s².
255 ///
256 /// The torque is applied continuously over the physics step and cleared afterwards.
257 ///
258 /// By default, a non-zero torque will wake up the body if it is sleeping. This can be prevented
259 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
260 #[cfg(feature = "3d")]
261 #[inline]
262 fn apply_local_torque(&mut self, torque: AngularVector) {
263 if torque != AngularVector::ZERO && self.try_wake_up() {
264 let acceleration = self.inverse_angular_inertia() * torque;
265 self.accumulated_local_acceleration_mut().angular += acceleration;
266 }
267 }
268
269 /// Applies a linear impulse at the center of mass in world space. The unit is typically N⋅s or kg⋅m/s.
270 ///
271 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
272 ///
273 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
274 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
275 #[inline]
276 fn apply_linear_impulse(&mut self, impulse: Vector) {
277 if impulse != Vector::ZERO && self.try_wake_up() {
278 let effective_inverse_mass = self
279 .locked_axes()
280 .apply_to_vec(Vector::splat(self.inverse_mass()));
281 let delta_vel = effective_inverse_mass * impulse;
282 *self.linear_velocity_mut() += delta_vel;
283 }
284 }
285
286 /// Applies a linear impulse at the given point in world space. The unit is typically N⋅s or kg⋅m/s.
287 ///
288 /// If the point is not at the center of mass, the impulse will also generate an angular impulse.
289 ///
290 /// The impulse modifies the [`LinearVelocity`] and [`AngularVelocity`] of the body immediately.
291 ///
292 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
293 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
294 ///
295 /// # Note
296 ///
297 /// If the [`Transform`] of the body is modified before applying the impulse,
298 /// the torque will be computed using an outdated global center of mass.
299 /// This may cause problems when applying a impulse right after teleporting
300 /// an entity, as the torque could grow very large if the distance between the point
301 /// and old center of mass is large.
302 ///
303 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
304 /// to update the global physics transform after modifying [`Transform`].
305 ///
306 /// [`Transform`]: bevy::transform::components::Transform
307 #[inline]
308 fn apply_linear_impulse_at_point(&mut self, impulse: Vector, world_point: Vector) {
309 self.apply_linear_impulse(impulse);
310 self.apply_angular_impulse(cross(world_point - self.global_center_of_mass(), impulse));
311 }
312
313 /// Applies a linear impulse in local space. The unit is typically N⋅s or kg⋅m/s.
314 ///
315 /// The impulse modifies the [`LinearVelocity`] of the body immediately.
316 ///
317 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
318 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
319 #[inline]
320 fn apply_local_linear_impulse(&mut self, impulse: Vector) {
321 if impulse != Vector::ZERO && self.try_wake_up() {
322 let world_impulse = self.rot() * impulse;
323 let effective_inverse_mass = self
324 .locked_axes()
325 .apply_to_vec(Vector::splat(self.inverse_mass()));
326 let delta_vel = effective_inverse_mass * world_impulse;
327 *self.linear_velocity_mut() += delta_vel;
328 }
329 }
330
331 /// Applies an angular impulse in world space. The unit is typically N⋅m⋅s or kg⋅m²/s.
332 ///
333 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
334 ///
335 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
336 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
337 #[inline]
338 fn apply_angular_impulse(&mut self, impulse: AngularVector) {
339 if impulse != AngularVector::ZERO && self.try_wake_up() {
340 let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
341 let delta_vel = effective_inverse_angular_inertia * impulse;
342 *self.angular_velocity_mut() += delta_vel;
343 }
344 }
345
346 /// Applies an angular impulse in local space. The unit is typically N⋅m⋅s or kg⋅m²/s.
347 ///
348 /// The impulse modifies the [`AngularVelocity`] of the body immediately.
349 ///
350 /// By default, a non-zero impulse will wake up the body if it is sleeping. This can be prevented
351 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
352 #[cfg(feature = "3d")]
353 #[inline]
354 fn apply_local_angular_impulse(&mut self, impulse: AngularVector) {
355 if impulse != AngularVector::ZERO && self.try_wake_up() {
356 let world_impulse = self.rot() * impulse;
357 let effective_inverse_angular_inertia = self.effective_inverse_angular_inertia();
358 let delta_vel = effective_inverse_angular_inertia * world_impulse;
359 *self.angular_velocity_mut() += delta_vel;
360 }
361 }
362
363 /// Applies a linear acceleration, ignoring mass. The unit is typically m/s².
364 ///
365 /// The acceleration is applied continuously over the physics step and cleared afterwards.
366 ///
367 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
368 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
369 #[inline]
370 fn apply_linear_acceleration(&mut self, acceleration: Vector) {
371 if acceleration != Vector::ZERO && self.try_wake_up() {
372 self.integration_data_mut()
373 .apply_linear_acceleration(acceleration);
374 }
375 }
376
377 /// Applies a linear acceleration at the given point in world space. The unit is typically m/s².
378 ///
379 /// If the point is not at the center of mass, the acceleration will also generate an angular acceleration.
380 ///
381 /// The acceleration is applied continuously over the physics step and cleared afterwards.
382 ///
383 /// By default, a non-zero acceleration 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 ///
386 /// # Note
387 ///
388 /// If the [`Transform`] of the body is modified before applying the acceleration,
389 /// the angular acceleration will be computed using an outdated global center of mass.
390 /// This may cause problems when applying a acceleration right after teleporting
391 /// an entity, as the angular acceleration could grow very large if the distance between the point
392 /// and old center of mass is large.
393 ///
394 /// In case this is causing problems, consider using the [`PhysicsTransformHelper`]
395 /// to update the global physics transform after modifying [`Transform`].
396 ///
397 /// [`Transform`]: bevy::transform::components::Transform
398 #[inline]
399 fn apply_linear_acceleration_at_point(&mut self, acceleration: Vector, world_point: Vector) {
400 self.apply_linear_acceleration(acceleration);
401 self.apply_angular_acceleration(cross(
402 world_point - self.global_center_of_mass(),
403 acceleration,
404 ));
405 }
406
407 /// Applies a linear acceleration in local space, ignoring mass. The unit is typically m/s².
408 ///
409 /// The acceleration is applied continuously over the physics step and cleared afterwards.
410 ///
411 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
412 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
413 #[inline]
414 fn apply_local_linear_acceleration(&mut self, acceleration: Vector) {
415 if acceleration != Vector::ZERO && self.try_wake_up() {
416 self.accumulated_local_acceleration_mut().linear += acceleration;
417 }
418 }
419
420 /// Applies an angular acceleration, ignoring angular inertia. The unit is rad/s².
421 ///
422 /// The acceleration is applied continuously over the physics step and cleared afterwards.
423 ///
424 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
425 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
426 #[inline]
427 fn apply_angular_acceleration(&mut self, acceleration: AngularVector) {
428 if acceleration != AngularVector::ZERO && self.try_wake_up() {
429 self.integration_data_mut()
430 .apply_angular_acceleration(acceleration);
431 }
432 }
433
434 /// Applies an angular acceleration in local space, ignoring angular inertia. The unit is rad/s².
435 ///
436 /// The acceleration is applied continuously over the physics step and cleared afterwards.
437 ///
438 /// By default, a non-zero acceleration will wake up the body if it is sleeping. This can be prevented
439 /// by first calling [`ForcesItem::non_waking`] to get a [`NonWakingForcesItem`].
440 #[cfg(feature = "3d")]
441 #[inline]
442 fn apply_local_angular_acceleration(&mut self, acceleration: AngularVector) {
443 if acceleration != AngularVector::ZERO && self.try_wake_up() {
444 self.accumulated_local_acceleration_mut().angular += acceleration;
445 }
446 }
447
448 /// Returns the linear acceleration that the body has accumulated
449 /// before the physics step in world space, including acceleration
450 /// caused by forces.
451 ///
452 /// This does not include gravity, contact forces, or joint forces.
453 /// Only forces and accelerations applied through [`Forces`] are included.
454 #[inline]
455 fn accumulated_linear_acceleration(&self) -> Vector {
456 // The linear increment is treated as linear acceleration until the integration step.
457 let world_linear_acceleration = self.integration_data().linear_increment;
458 let local_linear_acceleration = self.accumulated_local_acceleration().linear;
459
460 // Return the total world-space linear acceleration.
461 self.locked_axes()
462 .apply_to_vec(world_linear_acceleration + self.rot() * local_linear_acceleration)
463 }
464
465 /// Returns the angular acceleration that the body has accumulated
466 /// before the physics step in world space, including acceleration
467 /// caused by torques.
468 ///
469 /// This does not include gravity, contact forces, or joint forces.
470 /// Only torques and accelerations applied through [`Forces`] are included.
471 #[cfg(feature = "2d")]
472 #[inline]
473 fn accumulated_angular_acceleration(&self) -> AngularVector {
474 // The angular increment is treated as angular acceleration until the integration step.
475 self.locked_axes()
476 .apply_to_angular_velocity(self.integration_data().angular_increment)
477 }
478
479 /// Returns the angular acceleration that the body has accumulated
480 /// before the physics step in world space, including acceleration
481 /// caused by torques.
482 ///
483 /// This does not include gravity, contact forces, or joint forces.
484 /// Only torques and accelerations applied through [`Forces`] are included.
485 #[cfg(feature = "3d")]
486 #[inline]
487 fn accumulated_angular_acceleration(&self) -> AngularVector {
488 // The angular increment is treated as angular acceleration until the integration step.
489 let world_angular_acceleration = self.integration_data().angular_increment;
490 let local_angular_acceleration = self.accumulated_local_acceleration().angular;
491
492 // Return the total world-space angular acceleration.
493 self.locked_axes().apply_to_angular_velocity(
494 world_angular_acceleration + self.rot() * local_angular_acceleration,
495 )
496 }
497
498 /// Resets the accumulated linear acceleration to zero.
499 #[inline]
500 fn reset_accumulated_linear_acceleration(&mut self) {
501 self.integration_data_mut().linear_increment = Vector::ZERO;
502 self.accumulated_local_acceleration_mut().linear = Vector::ZERO;
503 }
504
505 /// Resets the accumulated angular acceleration to zero.
506 #[inline]
507 fn reset_accumulated_angular_acceleration(&mut self) {
508 self.integration_data_mut().angular_increment = AngularVector::ZERO;
509 #[cfg(feature = "3d")]
510 {
511 self.accumulated_local_acceleration_mut().angular = AngularVector::ZERO;
512 }
513 }
514
515 /// Returns the [`Position`] of the body.
516 #[inline]
517 fn position(&self) -> &Position {
518 self.pos()
519 }
520
521 /// Returns the [`Rotation`] of the body.
522 #[inline]
523 fn rotation(&self) -> &Rotation {
524 self.rot()
525 }
526
527 /// Returns the [`LinearVelocity`] of the body in world space.
528 #[inline]
529 fn linear_velocity(&self) -> Vector {
530 self.lin_vel()
531 }
532
533 /// Returns a mutable reference to the [`LinearVelocity`] of the body in world space.
534 #[inline]
535 fn linear_velocity_mut(&mut self) -> &mut Vector {
536 self.lin_vel_mut()
537 }
538
539 /// Returns the [`AngularVelocity`] of the body in world space.
540 #[inline]
541 fn angular_velocity(&self) -> AngularVector {
542 self.ang_vel()
543 }
544
545 /// Returns a mutable reference to the [`AngularVelocity`] of the body in world space.
546 #[inline]
547 fn angular_velocity_mut(&mut self) -> &mut AngularVector {
548 self.ang_vel_mut()
549 }
550
551 /// Returns the velocity of a point in world space on the body.
552 #[inline]
553 #[doc(alias = "linear_velocity_at_point")]
554 fn velocity_at_point(&self, world_point: Vector) -> Vector {
555 let offset = world_point - self.global_center_of_mass();
556 #[cfg(feature = "2d")]
557 {
558 self.linear_velocity() + self.angular_velocity() * offset.perp()
559 }
560 #[cfg(feature = "3d")]
561 {
562 self.linear_velocity() + self.angular_velocity().cross(offset)
563 }
564 }
565}
566
567/// A trait to provide internal getters and helpers for [`RigidBodyForces`].
568trait RigidBodyForcesInternal {
569 fn pos(&self) -> &Position;
570 fn rot(&self) -> &Rotation;
571 fn lin_vel(&self) -> Vector;
572 fn lin_vel_mut(&mut self) -> &mut Vector;
573 fn ang_vel(&self) -> AngularVector;
574 fn ang_vel_mut(&mut self) -> &mut AngularVector;
575 fn inverse_mass(&self) -> Scalar;
576 #[cfg(feature = "3d")]
577 fn inverse_angular_inertia(&self) -> SymmetricTensor;
578 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor;
579 fn global_center_of_mass(&self) -> Vector;
580 fn locked_axes(&self) -> LockedAxes;
581 fn integration_data(&self) -> &VelocityIntegrationData;
582 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData;
583 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration;
584 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration;
585 fn try_wake_up(&mut self) -> bool;
586}
587
588impl RigidBodyForcesInternal for ForcesItem<'_, '_> {
589 #[inline]
590 fn pos(&self) -> &Position {
591 self.position
592 }
593 #[inline]
594 fn rot(&self) -> &Rotation {
595 self.rotation
596 }
597 #[inline]
598 fn lin_vel(&self) -> Vector {
599 self.linear_velocity.0
600 }
601 #[inline]
602 fn lin_vel_mut(&mut self) -> &mut Vector {
603 &mut self.linear_velocity.0
604 }
605 #[inline]
606 fn ang_vel(&self) -> AngularVector {
607 self.angular_velocity.0
608 }
609 #[inline]
610 fn ang_vel_mut(&mut self) -> &mut AngularVector {
611 &mut self.angular_velocity.0
612 }
613 #[inline]
614 fn inverse_mass(&self) -> Scalar {
615 self.mass.inverse()
616 }
617 #[inline]
618 #[cfg(feature = "3d")]
619 fn inverse_angular_inertia(&self) -> SymmetricTensor {
620 self.angular_inertia.inverse()
621 }
622 #[inline]
623 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
624 #[cfg(feature = "2d")]
625 let global_angular_inertia = *self.angular_inertia;
626 #[cfg(feature = "3d")]
627 let global_angular_inertia = self.angular_inertia.rotated(self.rotation.0);
628 self.locked_axes()
629 .apply_to_angular_inertia(global_angular_inertia)
630 .inverse()
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 integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
646 &mut self.integration
647 }
648 #[inline]
649 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
650 &self.accumulated_local_acceleration
651 }
652 #[inline]
653 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
654 &mut self.accumulated_local_acceleration
655 }
656 #[inline]
657 fn try_wake_up(&mut self) -> bool {
658 // Wake up the body. Return `true` to indicate that the body is awake.
659 if let Some(sleep_timer) = &mut self.sleep_timer {
660 sleep_timer.0 = 0.0;
661 }
662 true
663 }
664}
665
666impl RigidBodyForcesInternal for NonWakingForcesItem<'_, '_> {
667 #[inline]
668 fn pos(&self) -> &Position {
669 self.0.position()
670 }
671 #[inline]
672 fn rot(&self) -> &Rotation {
673 self.0.rot()
674 }
675 #[inline]
676 fn lin_vel(&self) -> Vector {
677 self.0.lin_vel()
678 }
679 #[inline]
680 fn lin_vel_mut(&mut self) -> &mut Vector {
681 self.0.lin_vel_mut()
682 }
683 #[inline]
684 fn ang_vel(&self) -> AngularVector {
685 self.0.ang_vel()
686 }
687 #[inline]
688 fn ang_vel_mut(&mut self) -> &mut AngularVector {
689 self.0.ang_vel_mut()
690 }
691 #[inline]
692 fn inverse_mass(&self) -> Scalar {
693 self.0.inverse_mass()
694 }
695 #[inline]
696 #[cfg(feature = "3d")]
697 fn inverse_angular_inertia(&self) -> SymmetricTensor {
698 self.0.inverse_angular_inertia()
699 }
700 #[inline]
701 fn effective_inverse_angular_inertia(&self) -> SymmetricTensor {
702 self.0.effective_inverse_angular_inertia()
703 }
704 #[inline]
705 fn global_center_of_mass(&self) -> Vector {
706 self.0.global_center_of_mass()
707 }
708 #[inline]
709 fn locked_axes(&self) -> LockedAxes {
710 self.0.locked_axes()
711 }
712 #[inline]
713 fn integration_data(&self) -> &VelocityIntegrationData {
714 self.0.integration_data()
715 }
716 #[inline]
717 fn integration_data_mut(&mut self) -> &mut VelocityIntegrationData {
718 self.0.integration_data_mut()
719 }
720 #[inline]
721 fn accumulated_local_acceleration(&self) -> &AccumulatedLocalAcceleration {
722 self.0.accumulated_local_acceleration()
723 }
724 #[inline]
725 fn accumulated_local_acceleration_mut(&mut self) -> &mut AccumulatedLocalAcceleration {
726 self.0.accumulated_local_acceleration_mut()
727 }
728 #[inline]
729 fn try_wake_up(&mut self) -> bool {
730 // Don't wake up the body.
731 // Return `true` if the body is already awake and forces should be applied.
732 !self.0.is_sleeping
733 }
734}