avian2d/dynamics/rigid_body/forces/
plugin.rs

1use crate::{
2    dynamics::{
3        integrator::{
4            self, CustomVelocityIntegration, IntegrationSystems, VelocityIntegrationData,
5        },
6        solver::{
7            SolverDiagnostics,
8            solver_body::{SolverBody, SolverBodyInertia},
9        },
10    },
11    prelude::*,
12};
13use bevy::prelude::*;
14
15use super::AccumulatedLocalAcceleration;
16
17/// A plugin for managing and applying external forces, torques, and accelerations for [rigid bodies](RigidBody).
18///
19/// See the [module-level documentation](crate::dynamics::rigid_body::forces) for more general information about forces in Avian.
20pub struct ForcePlugin;
21
22impl Plugin for ForcePlugin {
23    fn build(&self, app: &mut App) {
24        // Set up system sets.
25        app.configure_sets(
26            PhysicsSchedule,
27            (
28                ForceSystems::ApplyConstantForces
29                    .in_set(IntegrationSystems::UpdateVelocityIncrements)
30                    .before(integrator::pre_process_velocity_increments),
31                ForceSystems::Clear.in_set(SolverSystems::PostSubstep),
32            ),
33        );
34        app.configure_sets(
35            SubstepSchedule,
36            ForceSystems::ApplyLocalAcceleration
37                .in_set(IntegrationSystems::Velocity)
38                .before(integrator::integrate_velocities),
39        );
40
41        // Accumulate constant forces, torques, and accelerations.
42        app.add_systems(
43            PhysicsSchedule,
44            (
45                apply_constant_forces,
46                apply_constant_torques,
47                apply_constant_linear_acceleration,
48                apply_constant_angular_acceleration,
49                apply_constant_local_forces,
50                #[cfg(feature = "3d")]
51                apply_constant_local_torques,
52                apply_constant_local_linear_acceleration,
53                #[cfg(feature = "3d")]
54                apply_constant_local_angular_acceleration,
55            )
56                .chain()
57                .in_set(ForceSystems::ApplyConstantForces),
58        );
59
60        // Apply local forces and accelerations.
61        // This is done in the substepping loop, because the orientations of bodies can change between substeps.
62        app.add_systems(
63            SubstepSchedule,
64            apply_local_acceleration.in_set(ForceSystems::ApplyLocalAcceleration),
65        );
66
67        // Clear accumulated forces and accelerations.
68        app.add_systems(
69            PhysicsSchedule,
70            clear_accumulated_local_acceleration.in_set(ForceSystems::Clear),
71        );
72    }
73}
74
75/// System sets for managing and applying forces, torques, and accelerations for [rigid bodies](RigidBody).
76#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
77pub enum ForceSystems {
78    /// Adds [`ConstantForce`], [`ConstantTorque`], [`ConstantLinearAcceleration`], and [`ConstantAngularAcceleration`]
79    #[cfg_attr(
80        feature = "2d",
81        doc = "to [`VelocityIntegrationData`], and [`ConstantLocalForce`] and [`ConstantLocalLinearAcceleration`]"
82    )]
83    #[cfg_attr(
84        feature = "3d",
85        doc = "to [`VelocityIntegrationData`], and [`ConstantLocalForce`], [`ConstantLocalTorque`], [`ConstantLocalLinearAcceleration`], and [`ConstantLocalAngularAcceleration`]"
86    )]
87    /// to [`AccumulatedLocalAcceleration`].
88    ApplyConstantForces,
89    /// Applies [`AccumulatedLocalAcceleration`] to the linear and angular velocities of bodies.
90    ApplyLocalAcceleration,
91    /// Clears [`AccumulatedLocalAcceleration`] for all bodies.
92    Clear,
93}
94
95/// Applies [`ConstantForce`] to the accumulated forces.
96fn apply_constant_forces(
97    mut bodies: Query<(&mut VelocityIntegrationData, &ComputedMass, &ConstantForce)>,
98) {
99    bodies
100        .iter_mut()
101        .for_each(|(mut integration, mass, constant_force)| {
102            integration.linear_increment += mass.inverse() * constant_force.0;
103        })
104}
105
106/// Applies [`ConstantTorque`] to the accumulated torques.
107fn apply_constant_torques(
108    mut bodies: Query<(
109        &mut VelocityIntegrationData,
110        &SolverBodyInertia,
111        &ConstantTorque,
112    )>,
113) {
114    bodies
115        .iter_mut()
116        .for_each(|(mut integration, inertia, constant_torque)| {
117            integration.angular_increment +=
118                inertia.effective_inv_angular_inertia() * constant_torque.0;
119        })
120}
121
122/// Applies [`ConstantLinearAcceleration`] to the linear velocity increments.
123fn apply_constant_linear_acceleration(
124    mut bodies: Query<(&mut VelocityIntegrationData, &ConstantLinearAcceleration)>,
125) {
126    bodies
127        .iter_mut()
128        .for_each(|(mut integration, constant_acceleration)| {
129            integration.linear_increment += constant_acceleration.0;
130        })
131}
132
133/// Applies [`ConstantAngularAcceleration`] to the angular velocity increments.
134fn apply_constant_angular_acceleration(
135    mut bodies: Query<(&mut VelocityIntegrationData, &ConstantAngularAcceleration)>,
136) {
137    bodies
138        .iter_mut()
139        .for_each(|(mut integration, constant_acceleration)| {
140            integration.angular_increment += constant_acceleration.0;
141        })
142}
143
144/// Applies [`ConstantLocalForce`] to the accumulated forces.
145fn apply_constant_local_forces(
146    mut bodies: Query<(
147        &mut AccumulatedLocalAcceleration,
148        &ComputedMass,
149        &ConstantLocalForce,
150    )>,
151) {
152    bodies
153        .iter_mut()
154        .for_each(|(mut acceleration, mass, constant_force)| {
155            acceleration.linear += mass.inverse() * constant_force.0;
156        })
157}
158
159/// Applies [`ConstantLocalTorque`] to the accumulated torques.
160#[cfg(feature = "3d")]
161fn apply_constant_local_torques(
162    mut bodies: Query<(
163        &mut AccumulatedLocalAcceleration,
164        &ComputedAngularInertia,
165        &ConstantLocalTorque,
166    )>,
167) {
168    bodies
169        .iter_mut()
170        .for_each(|(mut acceleration, angular_inertia, constant_torque)| {
171            acceleration.angular += angular_inertia.inverse() * constant_torque.0;
172        })
173}
174
175/// Applies [`ConstantLocalLinearAcceleration`] to the accumulated local acceleration.
176fn apply_constant_local_linear_acceleration(
177    mut bodies: Query<(
178        &mut AccumulatedLocalAcceleration,
179        &ConstantLocalLinearAcceleration,
180    )>,
181) {
182    bodies
183        .iter_mut()
184        .for_each(|(mut acceleration, constant_acceleration)| {
185            acceleration.linear += constant_acceleration.0;
186        })
187}
188
189/// Applies [`ConstantLocalAngularAcceleration`] to the accumulated local acceleration.
190#[cfg(feature = "3d")]
191fn apply_constant_local_angular_acceleration(
192    mut bodies: Query<(
193        &mut AccumulatedLocalAcceleration,
194        &ConstantLocalAngularAcceleration,
195    )>,
196) {
197    bodies
198        .iter_mut()
199        .for_each(|(mut acceleration, constant_acceleration)| {
200            acceleration.angular += constant_acceleration.0;
201        })
202}
203
204/// Applies [`AccumulatedLocalAcceleration`] to the linear and angular velocity of bodies.
205///
206/// This should run in the substepping loop, just before [`IntegrationSystems::Velocity`].
207fn apply_local_acceleration(
208    mut bodies: Query<
209        (&mut SolverBody, &AccumulatedLocalAcceleration, &Rotation),
210        Without<CustomVelocityIntegration>,
211    >,
212    mut diagnostics: ResMut<SolverDiagnostics>,
213    time: Res<Time<Substeps>>,
214) {
215    let start = crate::utils::Instant::now();
216
217    let delta_secs = time.delta_secs_f64() as Scalar;
218
219    bodies
220        .iter_mut()
221        .for_each(|(mut body, acceleration, rotation)| {
222            let rotation = body.delta_rotation * *rotation;
223            let locked_axes = body.flags.locked_axes();
224
225            // Compute the world space velocity increments with locked axes applied.
226            let world_linear_acceleration =
227                locked_axes.apply_to_vec(rotation * acceleration.linear);
228            #[cfg(feature = "3d")]
229            let world_angular_acceleration =
230                locked_axes.apply_to_vec(rotation * acceleration.angular);
231
232            // Apply acceleration.
233            body.linear_velocity += world_linear_acceleration * delta_secs;
234            #[cfg(feature = "3d")]
235            {
236                body.angular_velocity += world_angular_acceleration * delta_secs;
237            }
238        });
239
240    diagnostics.integrate_velocities += start.elapsed();
241}
242
243fn clear_accumulated_local_acceleration(mut query: Query<&mut AccumulatedLocalAcceleration>) {
244    query.iter_mut().for_each(|mut acceleration| {
245        acceleration.linear = Vector::ZERO;
246        #[cfg(feature = "3d")]
247        {
248            acceleration.angular = Vector::ZERO;
249        }
250    });
251}