avian2d/dynamics/rigid_body/forces/
plugin.rs

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