avian2d/dynamics/rigid_body/forces/
plugin.rs1use 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
15pub struct ForcePlugin;
19
20impl Plugin for ForcePlugin {
21 fn build(&self, app: &mut App) {
22 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 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 app.add_systems(
61 SubstepSchedule,
62 apply_local_acceleration.in_set(ForceSystems::ApplyLocalAcceleration),
63 );
64
65 app.add_systems(
67 PhysicsSchedule,
68 clear_accumulated_local_acceleration.in_set(ForceSystems::Clear),
69 );
70 }
71}
72
73#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
75pub enum ForceSystems {
76 #[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 ApplyConstantForces,
87 ApplyLocalAcceleration,
89 Clear,
91}
92
93fn 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
104fn 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
120fn 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
131fn 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
142fn 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#[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
173fn 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#[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
202fn 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 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 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}