Skip to content

Commit 6a65e8f

Browse files
authored
Fix SleepingPlugin not being optional and refactor logic (#624)
# Objective Avian 0.2.0 has a regression from 0.1 where the `TimeSleeping` component is required, but it is only added automatically (as a required component) if the `SleepingPlugin` is enabled. This means that disabling the `SleepingPlugin` breaks physics. ## Solution Make `TimeSleeping` properly optional for rigid bodies. I also added a `WakeUpBody` `Command` to clean up some logic and abstract away resetting `TimeSleeping`.
1 parent 4577abd commit 6a65e8f

File tree

7 files changed

+44
-28
lines changed

7 files changed

+44
-28
lines changed

crates/avian2d/examples/one_way_platform_2d.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ fn pass_through_one_way_platform(
174174
if keyboard_input.pressed(KeyCode::ArrowDown) && keyboard_input.pressed(KeyCode::Space) {
175175
*pass_through_one_way_platform = PassThroughOneWayPlatform::Always;
176176

177-
// Wake up body when it's allowed to drop down.
177+
// Wake up the body when it's allowed to drop down.
178178
// Otherwise it won't fall because gravity isn't simulated.
179-
commands.entity(entity).remove::<Sleeping>();
179+
commands.queue(WakeUpBody(entity));
180180
} else {
181181
*pass_through_one_way_platform = PassThroughOneWayPlatform::ByNormal;
182182
}

src/collision/collider/backend.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -664,16 +664,18 @@ struct ColliderRemovalSystem(SystemId<In<ColliderParent>>);
664664
fn collider_removed(
665665
In(parent): In<ColliderParent>,
666666
mut commands: Commands,
667-
mut mass_prop_query: Query<&mut TimeSleeping>,
667+
mut sleep_query: Query<&mut TimeSleeping>,
668668
) {
669669
let parent = parent.get();
670670

671-
if let Ok(mut time_sleeping) = mass_prop_query.get_mut(parent) {
672-
let mut entity_commands = commands.entity(parent);
671+
let Some(mut entity_commands) = commands.get_entity(parent) else {
672+
return;
673+
};
673674

674-
// Queue the parent entity for mass property recomputation.
675-
entity_commands.insert(RecomputeMassProperties);
675+
// Queue the parent entity for mass property recomputation.
676+
entity_commands.insert(RecomputeMassProperties);
676677

678+
if let Ok(mut time_sleeping) = sleep_query.get_mut(parent) {
677679
// Wake up the rigid body since removing the collider could also remove active contacts.
678680
entity_commands.remove::<Sleeping>();
679681
time_sleeping.0 = 0.0;

src/collision/narrow_phase.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -724,9 +724,9 @@ impl<C: AnyCollider> NarrowPhase<'_, '_, C> {
724724
// When an active body collides with a sleeping body, wake up the sleeping body.
725725
self.parallel_commands.command_scope(|mut commands| {
726726
if body1.is_sleeping {
727-
commands.entity(body1.entity).remove::<Sleeping>();
727+
commands.queue(WakeUpBody(body1.entity));
728728
} else if body2.is_sleeping {
729-
commands.entity(body2.entity).remove::<Sleeping>();
729+
commands.queue(WakeUpBody(body2.entity));
730730
}
731731
});
732732

src/dynamics/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ pub mod prelude {
8787
},
8888
*,
8989
},
90-
sleeping::{DeactivationTime, SleepingPlugin, SleepingThreshold},
90+
sleeping::{DeactivationTime, SleepingPlugin, SleepingThreshold, WakeUpBody},
9191
solver::{
9292
joints::*,
9393
schedule::{SolverSchedulePlugin, SolverSet, SubstepCount, SubstepSchedule},

src/dynamics/rigid_body/world_query.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ pub struct RigidBodyQuery {
2929
pub restitution: Option<&'static Restitution>,
3030
pub locked_axes: Option<&'static LockedAxes>,
3131
pub dominance: Option<&'static Dominance>,
32-
pub time_sleeping: &'static mut TimeSleeping,
32+
pub time_sleeping: Option<&'static mut TimeSleeping>,
3333
pub is_sleeping: Has<Sleeping>,
3434
pub is_sensor: Has<Sensor>,
3535
}

src/dynamics/sleeping/mod.rs

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,24 @@ impl Default for DeactivationTime {
109109
}
110110
}
111111

112+
/// A [`Command`] that wakes up a [rigid body](RigidBody) by removing the [`Sleeping`] component
113+
/// and resetting the [`TimeSleeping`] to zero.
114+
pub struct WakeUpBody(pub Entity);
115+
116+
impl Command for WakeUpBody {
117+
fn apply(self, world: &mut World) {
118+
let Ok(mut entity_mut) = world.get_entity_mut(self.0) else {
119+
return;
120+
};
121+
122+
entity_mut.remove::<Sleeping>();
123+
124+
if let Some(mut time_sleeping) = entity_mut.get_mut::<TimeSleeping>() {
125+
time_sleeping.0 = 0.0;
126+
};
127+
}
128+
}
129+
112130
/// Adds the [`Sleeping`] component to bodies whose linear and anigular velocities have been
113131
/// under the [`SleepingThreshold`] for a duration indicated by [`DeactivationTime`].
114132
#[allow(clippy::type_complexity)]
@@ -205,7 +223,6 @@ pub(crate) fn wake_on_changed(
205223
Ref<Rotation>,
206224
Ref<LinearVelocity>,
207225
Ref<AngularVelocity>,
208-
&mut TimeSleeping,
209226
),
210227
(
211228
With<Sleeping>,
@@ -220,7 +237,7 @@ pub(crate) fn wake_on_changed(
220237
// These are not modified by the physics engine
221238
// and don't need special handling.
222239
Query<
223-
(Entity, &mut TimeSleeping),
240+
Entity,
224241
Or<(
225242
Changed<ExternalForce>,
226243
Changed<ExternalTorque>,
@@ -235,20 +252,18 @@ pub(crate) fn wake_on_changed(
235252
) {
236253
let this_run = system_tick.this_run();
237254

238-
for (entity, pos, rot, lin_vel, ang_vel, mut time_sleeping) in &mut query.p0() {
255+
for (entity, pos, rot, lin_vel, ang_vel) in &query.p0() {
239256
if is_changed_after_tick(pos, last_physics_tick.0, this_run)
240257
|| is_changed_after_tick(rot, last_physics_tick.0, this_run)
241258
|| is_changed_after_tick(lin_vel, last_physics_tick.0, this_run)
242259
|| is_changed_after_tick(ang_vel, last_physics_tick.0, this_run)
243260
{
244-
commands.entity(entity).remove::<Sleeping>();
245-
time_sleeping.0 = 0.0;
261+
commands.queue(WakeUpBody(entity));
246262
}
247263
}
248264

249-
for (entity, mut time_sleeping) in &mut query.p1() {
250-
commands.entity(entity).remove::<Sleeping>();
251-
time_sleeping.0 = 0.0;
265+
for entity in &query.p1() {
266+
commands.queue(WakeUpBody(entity));
252267
}
253268
}
254269

@@ -259,13 +274,9 @@ fn is_changed_after_tick<C: Component>(component_ref: Ref<C>, tick: Tick, this_r
259274

260275
/// Removes the [`Sleeping`] component from all sleeping bodies.
261276
/// Triggered automatically when [`Gravity`] is changed.
262-
fn wake_all_sleeping_bodies(
263-
mut commands: Commands,
264-
mut bodies: Query<(Entity, &mut TimeSleeping), With<Sleeping>>,
265-
) {
266-
for (entity, mut time_sleeping) in &mut bodies {
267-
commands.entity(entity).remove::<Sleeping>();
268-
time_sleeping.0 = 0.0;
277+
fn wake_all_sleeping_bodies(mut commands: Commands, bodies: Query<Entity, With<Sleeping>>) {
278+
for entity in &bodies {
279+
commands.queue(WakeUpBody(entity));
269280
}
270281
}
271282

src/dynamics/solver/xpbd/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -377,10 +377,13 @@ pub fn solve_constraint<C: XpbdConstraint<ENTITY_COUNT> + Component, const ENTIT
377377

378378
// At least one of the participating bodies is active, so wake up any sleeping bodies
379379
for body in &mut bodies {
380-
body.time_sleeping.0 = 0.0;
380+
// Reset the sleep timer
381+
if let Some(time_sleeping) = body.time_sleeping.as_mut() {
382+
time_sleeping.0 = 0.0;
383+
}
381384

382385
if body.is_sleeping {
383-
commands.entity(body.entity).remove::<Sleeping>();
386+
commands.queue(WakeUpBody(body.entity));
384387
}
385388
}
386389

0 commit comments

Comments
 (0)