bevy_rapier
bevy_rapier copied to clipboard
Despawn events are missed in fixed timestep simulation with low tick rate
Detection for despawns/removed components are now backed by events (#324). However, since events only persist for 2 frames, they will likely be missed by a fixed timestep simulation with low tick rate. This results in colliders/rigid bodies still persisting when they should have been despawned.
Here is an example where a cube is despawned, but the collider remains visible:
Example
use bevy::prelude::*;
use bevy_rapier3d::prelude::*;
const PHYSICS_DELTA: f32 = 1.0 / 4.0;
fn main() {
App::new()
.insert_resource(ClearColor(Color::BLACK))
.insert_resource(RapierConfiguration {
timestep_mode: TimestepMode::Fixed {
dt: PHYSICS_DELTA,
substeps: 1,
},
..Default::default()
})
.insert_resource(FixedTime::new_from_secs(PHYSICS_DELTA))
.add_plugins(DefaultPlugins)
.add_plugin(RapierPhysicsPlugin::<NoUserData>::default().with_default_system_setup(false))
.add_plugin(RapierDebugRenderPlugin::default())
.add_startup_system(setup)
.edit_schedule(CoreSchedule::FixedUpdate, |schedule| {
schedule
.configure_sets(
(
PhysicsSet::SyncBackend,
PhysicsSet::SyncBackendFlush,
PhysicsSet::StepSimulation,
PhysicsSet::Writeback,
)
.chain(),
)
.add_systems(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::SyncBackend)
.in_base_set(PhysicsSet::SyncBackend),
)
.add_systems(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::SyncBackendFlush)
.in_base_set(PhysicsSet::SyncBackendFlush),
)
.add_systems(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::StepSimulation)
.in_base_set(PhysicsSet::StepSimulation),
)
.add_system(despawn.in_base_set(PhysicsSet::StepSimulation))
.add_systems(
RapierPhysicsPlugin::<NoUserData>::get_systems(PhysicsSet::Writeback)
.in_base_set(PhysicsSet::Writeback),
);
})
// .add_system(systems::sync_removals.in_base_set(CoreSet::Last))
.run();
}
fn setup(mut commands: Commands) {
// Camera
commands.spawn(Camera3dBundle {
transform: Transform::from_xyz(5.0, 5.0, 5.0).looking_at(Vec3::ZERO, Vec3::Y),
..Default::default()
});
// Cube
commands.spawn((TransformBundle::IDENTITY, Collider::cuboid(1.0, 1.0, 1.0)));
}
fn despawn(cube_q: Query<Entity, With<Collider>>, mut commands: Commands) {
if let Ok(entity) = cube_q.get_single() {
println!("Despawn!");
commands.entity(entity).despawn();
}
}
Adding the sync_removals
system to CoreSet::Last
resolves this issue. Should this perhaps be the default, as it was before with the DetectDespawn
stage?