avian3d/dynamics/rigid_body/forces/
plugin.rs1use crate::{
2 dynamics::{
3 integrator::{
4 self, CustomVelocityIntegration, IntegrationSystems, VelocityIntegrationData,
5 },
6 solver::{
7 SolverDiagnostics,
8 solver_body::{SolverBodies, SolverBodyIndex},
9 },
10 },
11 prelude::*,
12};
13use bevy::prelude::*;
14
15use super::AccumulatedLocalAcceleration;
16
17pub struct ForcePlugin;
21
22impl Plugin for ForcePlugin {
23 fn build(&self, app: &mut App) {
24 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 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 app.add_systems(
63 SubstepSchedule,
64 apply_local_acceleration.in_set(ForceSystems::ApplyLocalAcceleration),
65 );
66
67 app.add_systems(
69 PhysicsSchedule,
70 clear_accumulated_local_acceleration.in_set(ForceSystems::Clear),
71 );
72 }
73}
74
75#[derive(SystemSet, Clone, Copy, Debug, PartialEq, Eq, Hash)]
77pub enum ForceSystems {
78 #[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 ApplyConstantForces,
89 ApplyLocalAcceleration,
91 Clear,
93}
94
95fn 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
106fn apply_constant_torques(
108 solver_bodies: Res<SolverBodies>,
109 mut bodies: Query<(
110 &SolverBodyIndex,
111 &mut VelocityIntegrationData,
112 &ConstantTorque,
113 )>,
114) {
115 bodies
116 .iter_mut()
117 .for_each(|(index, mut integration, constant_torque)| {
118 let Some(inertia) = solver_bodies.get_inertia(*index) else {
119 return;
120 };
121 integration.angular_increment +=
122 inertia.effective_inv_angular_inertia() * constant_torque.0;
123 })
124}
125
126fn apply_constant_linear_acceleration(
128 mut bodies: Query<(&mut VelocityIntegrationData, &ConstantLinearAcceleration)>,
129) {
130 bodies
131 .iter_mut()
132 .for_each(|(mut integration, constant_acceleration)| {
133 integration.linear_increment += constant_acceleration.0;
134 })
135}
136
137fn apply_constant_angular_acceleration(
139 mut bodies: Query<(&mut VelocityIntegrationData, &ConstantAngularAcceleration)>,
140) {
141 bodies
142 .iter_mut()
143 .for_each(|(mut integration, constant_acceleration)| {
144 integration.angular_increment += constant_acceleration.0;
145 })
146}
147
148fn apply_constant_local_forces(
150 mut bodies: Query<(
151 &mut AccumulatedLocalAcceleration,
152 &ComputedMass,
153 &ConstantLocalForce,
154 )>,
155) {
156 bodies
157 .iter_mut()
158 .for_each(|(mut acceleration, mass, constant_force)| {
159 acceleration.linear += mass.inverse() * constant_force.0;
160 })
161}
162
163#[cfg(feature = "3d")]
165fn apply_constant_local_torques(
166 mut bodies: Query<(
167 &mut AccumulatedLocalAcceleration,
168 &ComputedAngularInertia,
169 &ConstantLocalTorque,
170 )>,
171) {
172 bodies
173 .iter_mut()
174 .for_each(|(mut acceleration, angular_inertia, constant_torque)| {
175 acceleration.angular += angular_inertia.inverse() * constant_torque.0;
176 })
177}
178
179fn apply_constant_local_linear_acceleration(
181 mut bodies: Query<(
182 &mut AccumulatedLocalAcceleration,
183 &ConstantLocalLinearAcceleration,
184 )>,
185) {
186 bodies
187 .iter_mut()
188 .for_each(|(mut acceleration, constant_acceleration)| {
189 acceleration.linear += constant_acceleration.0;
190 })
191}
192
193#[cfg(feature = "3d")]
195fn apply_constant_local_angular_acceleration(
196 mut bodies: Query<(
197 &mut AccumulatedLocalAcceleration,
198 &ConstantLocalAngularAcceleration,
199 )>,
200) {
201 bodies
202 .iter_mut()
203 .for_each(|(mut acceleration, constant_acceleration)| {
204 acceleration.angular += constant_acceleration.0;
205 })
206}
207
208fn apply_local_acceleration(
212 mut solver_bodies: ResMut<SolverBodies>,
213 bodies: Query<
214 (&SolverBodyIndex, &AccumulatedLocalAcceleration, &Rotation),
215 Without<CustomVelocityIntegration>,
216 >,
217 mut diagnostics: ResMut<SolverDiagnostics>,
218 time: Res<Time<Substeps>>,
219) {
220 let start = crate::utils::Instant::now();
221
222 let delta_secs = time.delta_secs();
223
224 let access = solver_bodies.access();
225
226 bodies.iter().for_each(|(index, acceleration, rotation)| {
227 let body = unsafe { access.body_unchecked_mut(*index) };
229
230 let rotation = body.delta_rotation * Rot::from(*rotation);
231 let locked_axes = body.flags.locked_axes();
232
233 let world_linear_acceleration = locked_axes.apply_to_vec(rotation * acceleration.linear);
235 #[cfg(feature = "3d")]
236 let world_angular_acceleration = locked_axes.apply_to_vec(rotation * acceleration.angular);
237
238 body.linear_velocity += world_linear_acceleration * delta_secs;
240 #[cfg(feature = "3d")]
241 {
242 body.angular_velocity += world_angular_acceleration * delta_secs;
243 }
244 });
245
246 diagnostics.integrate_velocities += start.elapsed();
247}
248
249fn clear_accumulated_local_acceleration(
250 mut query: Query<&mut AccumulatedLocalAcceleration, Changed<AccumulatedLocalAcceleration>>,
251) {
252 for mut acceleration in &mut query {
253 let acceleration = acceleration.bypass_change_detection();
256 acceleration.linear = Vector::ZERO;
257 #[cfg(feature = "3d")]
258 {
259 acceleration.angular = AngularVector::ZERO;
260 }
261 }
262}