Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix SleepingPlugin not being optional and add WakeUpBody command #624

Merged
merged 1 commit into from
Jan 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/avian2d/examples/one_way_platform_2d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ fn pass_through_one_way_platform(
if keyboard_input.pressed(KeyCode::ArrowDown) && keyboard_input.pressed(KeyCode::Space) {
*pass_through_one_way_platform = PassThroughOneWayPlatform::Always;

// Wake up body when it's allowed to drop down.
// Wake up the body when it's allowed to drop down.
// Otherwise it won't fall because gravity isn't simulated.
commands.entity(entity).remove::<Sleeping>();
commands.queue(WakeUpBody(entity));
} else {
*pass_through_one_way_platform = PassThroughOneWayPlatform::ByNormal;
}
Expand Down
12 changes: 7 additions & 5 deletions src/collision/collider/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -664,16 +664,18 @@ struct ColliderRemovalSystem(SystemId<In<ColliderParent>>);
fn collider_removed(
In(parent): In<ColliderParent>,
mut commands: Commands,
mut mass_prop_query: Query<&mut TimeSleeping>,
mut sleep_query: Query<&mut TimeSleeping>,
) {
let parent = parent.get();

if let Ok(mut time_sleeping) = mass_prop_query.get_mut(parent) {
let mut entity_commands = commands.entity(parent);
let Some(mut entity_commands) = commands.get_entity(parent) else {
return;
};

// Queue the parent entity for mass property recomputation.
entity_commands.insert(RecomputeMassProperties);
// Queue the parent entity for mass property recomputation.
entity_commands.insert(RecomputeMassProperties);

if let Ok(mut time_sleeping) = sleep_query.get_mut(parent) {
// Wake up the rigid body since removing the collider could also remove active contacts.
entity_commands.remove::<Sleeping>();
time_sleeping.0 = 0.0;
Expand Down
4 changes: 2 additions & 2 deletions src/collision/narrow_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -724,9 +724,9 @@ impl<C: AnyCollider> NarrowPhase<'_, '_, C> {
// When an active body collides with a sleeping body, wake up the sleeping body.
self.parallel_commands.command_scope(|mut commands| {
if body1.is_sleeping {
commands.entity(body1.entity).remove::<Sleeping>();
commands.queue(WakeUpBody(body1.entity));
} else if body2.is_sleeping {
commands.entity(body2.entity).remove::<Sleeping>();
commands.queue(WakeUpBody(body2.entity));
}
});

Expand Down
2 changes: 1 addition & 1 deletion src/dynamics/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ pub mod prelude {
},
*,
},
sleeping::{DeactivationTime, SleepingPlugin, SleepingThreshold},
sleeping::{DeactivationTime, SleepingPlugin, SleepingThreshold, WakeUpBody},
solver::{
joints::*,
schedule::{SolverSchedulePlugin, SolverSet, SubstepCount, SubstepSchedule},
Expand Down
2 changes: 1 addition & 1 deletion src/dynamics/rigid_body/world_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub struct RigidBodyQuery {
pub restitution: Option<&'static Restitution>,
pub locked_axes: Option<&'static LockedAxes>,
pub dominance: Option<&'static Dominance>,
pub time_sleeping: &'static mut TimeSleeping,
pub time_sleeping: Option<&'static mut TimeSleeping>,
pub is_sleeping: Has<Sleeping>,
pub is_sensor: Has<Sensor>,
}
Expand Down
41 changes: 26 additions & 15 deletions src/dynamics/sleeping/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,24 @@ impl Default for DeactivationTime {
}
}

/// A [`Command`] that wakes up a [rigid body](RigidBody) by removing the [`Sleeping`] component
/// and resetting the [`TimeSleeping`] to zero.
pub struct WakeUpBody(pub Entity);

impl Command for WakeUpBody {
fn apply(self, world: &mut World) {
let Ok(mut entity_mut) = world.get_entity_mut(self.0) else {
return;
};

entity_mut.remove::<Sleeping>();

if let Some(mut time_sleeping) = entity_mut.get_mut::<TimeSleeping>() {
time_sleeping.0 = 0.0;
};
}
}

/// Adds the [`Sleeping`] component to bodies whose linear and anigular velocities have been
/// under the [`SleepingThreshold`] for a duration indicated by [`DeactivationTime`].
#[allow(clippy::type_complexity)]
Expand Down Expand Up @@ -205,7 +223,6 @@ pub(crate) fn wake_on_changed(
Ref<Rotation>,
Ref<LinearVelocity>,
Ref<AngularVelocity>,
&mut TimeSleeping,
),
(
With<Sleeping>,
Expand All @@ -220,7 +237,7 @@ pub(crate) fn wake_on_changed(
// These are not modified by the physics engine
// and don't need special handling.
Query<
(Entity, &mut TimeSleeping),
Entity,
Or<(
Changed<ExternalForce>,
Changed<ExternalTorque>,
Expand All @@ -235,20 +252,18 @@ pub(crate) fn wake_on_changed(
) {
let this_run = system_tick.this_run();

for (entity, pos, rot, lin_vel, ang_vel, mut time_sleeping) in &mut query.p0() {
for (entity, pos, rot, lin_vel, ang_vel) in &query.p0() {
if is_changed_after_tick(pos, last_physics_tick.0, this_run)
|| is_changed_after_tick(rot, last_physics_tick.0, this_run)
|| is_changed_after_tick(lin_vel, last_physics_tick.0, this_run)
|| is_changed_after_tick(ang_vel, last_physics_tick.0, this_run)
{
commands.entity(entity).remove::<Sleeping>();
time_sleeping.0 = 0.0;
commands.queue(WakeUpBody(entity));
}
}

for (entity, mut time_sleeping) in &mut query.p1() {
commands.entity(entity).remove::<Sleeping>();
time_sleeping.0 = 0.0;
for entity in &query.p1() {
commands.queue(WakeUpBody(entity));
}
}

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

/// Removes the [`Sleeping`] component from all sleeping bodies.
/// Triggered automatically when [`Gravity`] is changed.
fn wake_all_sleeping_bodies(
mut commands: Commands,
mut bodies: Query<(Entity, &mut TimeSleeping), With<Sleeping>>,
) {
for (entity, mut time_sleeping) in &mut bodies {
commands.entity(entity).remove::<Sleeping>();
time_sleeping.0 = 0.0;
fn wake_all_sleeping_bodies(mut commands: Commands, bodies: Query<Entity, With<Sleeping>>) {
for entity in &bodies {
commands.queue(WakeUpBody(entity));
}
}

Expand Down
7 changes: 5 additions & 2 deletions src/dynamics/solver/xpbd/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,13 @@ pub fn solve_constraint<C: XpbdConstraint<ENTITY_COUNT> + Component, const ENTIT

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

if body.is_sleeping {
commands.entity(body.entity).remove::<Sleeping>();
commands.queue(WakeUpBody(body.entity));
}
}

Expand Down
Loading