diff --git a/bevy_rapier2d/Cargo.toml b/bevy_rapier2d/Cargo.toml index 6ad71b7c..1685ada8 100644 --- a/bevy_rapier2d/Cargo.toml +++ b/bevy_rapier2d/Cargo.toml @@ -37,8 +37,8 @@ async-collider = [ ] [dependencies] -bevy = { version = "0.9.0", default-features = false, features = ["bevy_asset", "bevy_scene"] } -nalgebra = { version = "0.32.0", features = [ "convert-glam022" ] } +bevy = { version = "0.10", default-features = false, features = ["bevy_asset", "bevy_scene"] } +nalgebra = { version = "0.32.2", features = [ "convert-glam023" ] } # Don't enable the default features because we don't need the ColliderSet/RigidBodySet rapier2d = "0.17.0" bitflags = "1" @@ -47,10 +47,10 @@ log = "0.4" serde = { version = "1", features = [ "derive" ], optional = true} [dev-dependencies] -bevy = { version = "0.9.0", default-features = false, features = ["x11"]} +bevy = { version = "0.10", default-features = false, features = ["x11"]} oorandom = "11" approx = "0.5.1" -glam = { version = "0.22", features = [ "approx" ] } +glam = { version = "0.23", features = [ "approx" ] } [package.metadata.docs.rs] # Enable all the features when building the docs on docs.rs diff --git a/bevy_rapier2d/examples/custom_system_setup2.rs b/bevy_rapier2d/examples/custom_system_setup2.rs index 99c6ddbe..49a6f92c 100644 --- a/bevy_rapier2d/examples/custom_system_setup2.rs +++ b/bevy_rapier2d/examples/custom_system_setup2.rs @@ -1,41 +1,8 @@ -use bevy::{core::FrameCount, prelude::*}; +use bevy::{core::FrameCount, ecs::schedule::ScheduleLabel, prelude::*}; use bevy_rapier2d::prelude::*; -struct SpecialStagingPlugin { - schedule: Schedule, -} - -impl SpecialStagingPlugin { - pub fn new(schedule: Schedule) -> Self { - Self { schedule } - } -} - -impl SpecialStagingPlugin { - fn build(self, app: &mut App) { - app.add_stage_after( - CoreStage::Update, - "special_staging_plugin_stage", - SpecialStage::new(self.schedule), - ); - } -} - -struct SpecialStage { - schedule: Schedule, -} - -impl SpecialStage { - pub fn new(schedule: Schedule) -> Self { - Self { schedule } - } -} - -impl Stage for SpecialStage { - fn run(&mut self, world: &mut World) { - self.schedule.run_once(world); - } -} +#[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone)] +struct SpecialSchedule; fn main() { let mut app = App::new(); @@ -48,71 +15,67 @@ fn main() { .add_plugins(DefaultPlugins) .add_plugin(RapierDebugRenderPlugin::default()) .add_startup_system(setup_graphics) - .add_startup_system(setup_physics); - - // Do the stage setup however we want, maybe in a special plugin that has - // its very own schedule - SpecialStagingPlugin::new( - Schedule::default() - .with_stage( - PhysicsStages::SyncBackend, - SystemStage::parallel().with_system_set( - RapierPhysicsPlugin::::get_systems(PhysicsStages::SyncBackend), - ), - ) - .with_stage_after( - PhysicsStages::SyncBackend, - PhysicsStages::StepSimulation, - SystemStage::parallel() - .with_system(despawn_one_box) // We can add a special despawn to determine cleanup later - .with_system_set(RapierPhysicsPlugin::::get_systems( - PhysicsStages::StepSimulation, - )), - ) - .with_stage_after( - PhysicsStages::StepSimulation, - PhysicsStages::Writeback, - SystemStage::parallel().with_system_set( - RapierPhysicsPlugin::::get_systems(PhysicsStages::Writeback), - ), - ), - ) - .build(&mut app); - - // Be sure to setup all four stages - app.add_stage_before( - CoreStage::Last, - PhysicsStages::DetectDespawn, - SystemStage::parallel().with_system_set(RapierPhysicsPlugin::::get_systems( - PhysicsStages::DetectDespawn, - )), + .add_startup_system(setup_physics) + .add_system( + (|world: &mut World| { + world.run_schedule(SpecialSchedule); + }) + .in_base_set(CoreSet::PostUpdate), + ); + + // Do the setup however we want, maybe in its very own schedule + let mut schedule = Schedule::new(); + + schedule.configure_sets( + ( + PhysicsSet::SyncBackend, + PhysicsSet::SyncBackendFlush, + PhysicsSet::StepSimulation, + PhysicsSet::Writeback, + ) + .chain(), + ); + + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::SyncBackend) + .in_base_set(PhysicsSet::SyncBackend), + ); + + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::SyncBackendFlush) + .in_base_set(PhysicsSet::SyncBackendFlush), ); - app.add_plugin( - RapierPhysicsPlugin::::default() - .with_physics_scale(100.) - .with_default_system_setup(false), + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::StepSimulation) + .in_base_set(PhysicsSet::StepSimulation), ); + schedule.add_system(despawn_one_box.in_base_set(PhysicsSet::StepSimulation)); - app.run(); + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::Writeback) + .in_base_set(PhysicsSet::Writeback), + ); + + app.add_schedule(SpecialSchedule, schedule) + .add_plugin( + RapierPhysicsPlugin::::default() + .with_physics_scale(100.) + .with_default_system_setup(false), + ) + .run(); } fn despawn_one_box( mut commands: Commands, - mut frame_count: ResMut, + frame_count: ResMut, query: Query, With)>, ) { - frame_count.0 += 1; - // Delete a box every 10 frames if frame_count.0 % 10 == 0 && !query.is_empty() { - let count = query.iter().count(); - if let Some(entity) = query - .iter() - .skip(frame_count.0 as usize % count) // Get a "random" box to make sim interesting - .take(1) - .next() - { + let len = query.iter().len(); + // Get a "random" box to make sim interesting + if let Some(entity) = query.iter().nth(frame_count.0 as usize % len) { commands.entity(entity).despawn(); } } diff --git a/bevy_rapier2d/examples/debug_despawn2.rs b/bevy_rapier2d/examples/debug_despawn2.rs index 9577bb28..92cdd924 100644 --- a/bevy_rapier2d/examples/debug_despawn2.rs +++ b/bevy_rapier2d/examples/debug_despawn2.rs @@ -258,7 +258,7 @@ fn clear_filled_rows( } for row_blocks in blocks_per_row { - if row_blocks.len() == game.n_lanes as usize { + if row_blocks.len() == game.n_lanes { game.stats.cleared_blocks += game.n_lanes as i32; for block_entity in row_blocks { diff --git a/bevy_rapier2d/examples/events2.rs b/bevy_rapier2d/examples/events2.rs index 77c60f65..15b416a5 100644 --- a/bevy_rapier2d/examples/events2.rs +++ b/bevy_rapier2d/examples/events2.rs @@ -13,7 +13,7 @@ fn main() { .add_plugin(RapierDebugRenderPlugin::default()) .add_startup_system(setup_graphics) .add_startup_system(setup_physics) - .add_system_to_stage(CoreStage::PostUpdate, display_events) + .add_system(display_events.in_base_set(CoreSet::PostUpdate)) .run(); } @@ -26,11 +26,11 @@ fn display_events( mut contact_force_events: EventReader, ) { for collision_event in collision_events.iter() { - println!("Received collision event: {:?}", collision_event); + println!("Received collision event: {collision_event:?}"); } for contact_force_event in contact_force_events.iter() { - println!("Received contact force event: {:?}", contact_force_event); + println!("Received contact force event: {contact_force_event:?}"); } } diff --git a/bevy_rapier2d/examples/player_movement2.rs b/bevy_rapier2d/examples/player_movement2.rs index 898b9557..bf273bd7 100644 --- a/bevy_rapier2d/examples/player_movement2.rs +++ b/bevy_rapier2d/examples/player_movement2.rs @@ -1,15 +1,14 @@ -use bevy::prelude::*; +use bevy::{prelude::*, window::WindowResolution}; use bevy_rapier2d::prelude::*; fn main() { App::new() .add_plugins(DefaultPlugins.set(WindowPlugin { - window: WindowDescriptor { + primary_window: Some(Window { + resolution: WindowResolution::new(1000., 1000.), title: "Player Movement Example".to_string(), - width: 1000.0, - height: 1000.0, - ..Default::default() - }, + ..default() + }), ..default() })) .add_startup_system(spawn_player) diff --git a/bevy_rapier3d/Cargo.toml b/bevy_rapier3d/Cargo.toml index 0af23b2e..28e8e5e8 100644 --- a/bevy_rapier3d/Cargo.toml +++ b/bevy_rapier3d/Cargo.toml @@ -38,8 +38,8 @@ headless = [ ] async-collider = [ ] [dependencies] -bevy = { version = "0.9.0", default-features = false, features = ["bevy_asset", "bevy_scene"] } -nalgebra = { version = "^0.32.0", features = [ "convert-glam022" ] } +bevy = { version = "0.10", default-features = false, features = ["bevy_asset", "bevy_scene"] } +nalgebra = { version = "0.32.2", features = [ "convert-glam023" ] } # Don't enable the default features because we don't need the ColliderSet/RigidBodySet rapier3d = "0.17.0" bitflags = "1" @@ -48,9 +48,9 @@ log = "0.4" serde = { version = "1", features = [ "derive" ], optional = true} [dev-dependencies] -bevy = { version = "0.9.0", default-features = false, features = ["x11"]} +bevy = { version = "0.10", default-features = false, features = ["x11"]} approx = "0.5.1" -glam = { version = "0.22", features = [ "approx" ] } +glam = { version = "0.23", features = [ "approx" ] } [package.metadata.docs.rs] # Enable all the features when building the docs on docs.rs diff --git a/bevy_rapier3d/examples/custom_system_setup3.rs b/bevy_rapier3d/examples/custom_system_setup3.rs index ddf315fe..3911afed 100644 --- a/bevy_rapier3d/examples/custom_system_setup3.rs +++ b/bevy_rapier3d/examples/custom_system_setup3.rs @@ -1,41 +1,8 @@ -use bevy::{core::FrameCount, prelude::*}; +use bevy::{core::FrameCount, ecs::schedule::ScheduleLabel, prelude::*}; use bevy_rapier3d::prelude::*; -struct SpecialStagingPlugin { - schedule: Schedule, -} - -impl SpecialStagingPlugin { - pub fn new(schedule: Schedule) -> Self { - Self { schedule } - } -} - -impl SpecialStagingPlugin { - fn build(self, app: &mut App) { - app.add_stage_after( - CoreStage::Update, - "special_staging_plugin_stage", - SpecialStage::new(self.schedule), - ); - } -} - -struct SpecialStage { - schedule: Schedule, -} - -impl SpecialStage { - pub fn new(schedule: Schedule) -> Self { - Self { schedule } - } -} - -impl Stage for SpecialStage { - fn run(&mut self, world: &mut World) { - self.schedule.run_once(world); - } -} +#[derive(ScheduleLabel, Hash, Debug, PartialEq, Eq, Clone)] +struct SpecialSchedule; fn main() { let mut app = App::new(); @@ -48,67 +15,63 @@ fn main() { .add_plugins(DefaultPlugins) .add_plugin(RapierDebugRenderPlugin::default()) .add_startup_system(setup_graphics) - .add_startup_system(setup_physics); - - // Do the stage setup however we want, maybe in a special plugin that has - // its very own schedule - SpecialStagingPlugin::new( - Schedule::default() - .with_stage( - PhysicsStages::SyncBackend, - SystemStage::parallel().with_system_set( - RapierPhysicsPlugin::::get_systems(PhysicsStages::SyncBackend), - ), - ) - .with_stage_after( - PhysicsStages::SyncBackend, - PhysicsStages::StepSimulation, - SystemStage::parallel() - .with_system(despawn_one_box) // We can add a special despawn to determine cleanup later - .with_system_set(RapierPhysicsPlugin::::get_systems( - PhysicsStages::StepSimulation, - )), - ) - .with_stage_after( - PhysicsStages::StepSimulation, - PhysicsStages::Writeback, - SystemStage::parallel().with_system_set( - RapierPhysicsPlugin::::get_systems(PhysicsStages::Writeback), - ), - ), - ) - .build(&mut app); - - // Be sure to setup all four stages - app.add_stage_before( - CoreStage::Last, - PhysicsStages::DetectDespawn, - SystemStage::parallel().with_system_set(RapierPhysicsPlugin::::get_systems( - PhysicsStages::DetectDespawn, - )), + .add_startup_system(setup_physics) + .add_system( + (|world: &mut World| { + world.run_schedule(SpecialSchedule); + }) + .in_base_set(CoreSet::PostUpdate), + ); + + // Do the setup however we want, maybe in its very own schedule + let mut schedule = Schedule::new(); + + schedule.configure_sets( + ( + PhysicsSet::SyncBackend, + PhysicsSet::SyncBackendFlush, + PhysicsSet::StepSimulation, + PhysicsSet::Writeback, + ) + .chain(), + ); + + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::SyncBackend) + .in_base_set(PhysicsSet::SyncBackend), + ); + + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::SyncBackendFlush) + .in_base_set(PhysicsSet::SyncBackendFlush), ); - app.add_plugin(RapierPhysicsPlugin::::default().with_default_system_setup(false)); + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::StepSimulation) + .in_base_set(PhysicsSet::StepSimulation), + ); + schedule.add_system(despawn_one_box.in_base_set(PhysicsSet::StepSimulation)); + + schedule.add_systems( + RapierPhysicsPlugin::::get_systems(PhysicsSet::Writeback) + .in_base_set(PhysicsSet::Writeback), + ); - app.run(); + app.add_schedule(SpecialSchedule, schedule) + .add_plugin(RapierPhysicsPlugin::::default().with_default_system_setup(false)) + .run(); } fn despawn_one_box( mut commands: Commands, - mut frame_count: ResMut, + frame_count: ResMut, query: Query, With)>, ) { - frame_count.0 += 1; - - // Delete a box every 10 frames - if frame_count.0 % 10 == 0 && !query.is_empty() { - let count = query.iter().count(); - if let Some(entity) = query - .iter() - .skip(frame_count.0 as usize % count) // Get a "random" box to make sim interesting - .take(1) - .next() - { + // Delete a box every 5 frames + if frame_count.0 % 5 == 0 && !query.is_empty() { + let len = query.iter().len(); + // Get a "random" box to make sim interesting + if let Some(entity) = query.iter().nth(frame_count.0 as usize % len) { commands.entity(entity).despawn(); } } diff --git a/bevy_rapier3d/examples/events3.rs b/bevy_rapier3d/examples/events3.rs index fb2b1660..15d65f57 100644 --- a/bevy_rapier3d/examples/events3.rs +++ b/bevy_rapier3d/examples/events3.rs @@ -13,7 +13,7 @@ fn main() { .add_plugin(RapierDebugRenderPlugin::default()) .add_startup_system(setup_graphics) .add_startup_system(setup_physics) - .add_system_to_stage(CoreStage::PostUpdate, display_events) + .add_system(display_events.in_base_set(CoreSet::PostUpdate)) .run(); } @@ -29,11 +29,11 @@ fn display_events( mut contact_force_events: EventReader, ) { for collision_event in collision_events.iter() { - println!("Received collision event: {:?}", collision_event); + println!("Received collision event: {collision_event:?}"); } for contact_force_event in contact_force_events.iter() { - println!("Received contact force event: {:?}", contact_force_event); + println!("Received contact force event: {contact_force_event:?}"); } } diff --git a/bevy_rapier3d/examples/ray_casting3.rs b/bevy_rapier3d/examples/ray_casting3.rs index 5490bc72..a408fc7c 100644 --- a/bevy_rapier3d/examples/ray_casting3.rs +++ b/bevy_rapier3d/examples/ray_casting3.rs @@ -72,20 +72,23 @@ pub fn setup_physics(mut commands: Commands) { fn cast_ray( mut commands: Commands, - windows: Res, + windows: Query<&Window>, rapier_context: Res, cameras: Query<(&Camera, &GlobalTransform)>, ) { + let window = windows.single(); + + let Some(cursor_position) = window.cursor_position() else { return; }; + // We will color in read the colliders hovered by the mouse. - for (camera, camera_transform) in cameras.iter() { + for (camera, camera_transform) in &cameras { // First, compute a ray from the mouse position. - let (ray_pos, ray_dir) = - ray_from_mouse_position(windows.get_primary().unwrap(), camera, camera_transform); + let Some(ray) = camera.viewport_to_world(camera_transform, cursor_position) else { return; }; // Then cast the ray. let hit = rapier_context.cast_ray( - ray_pos, - ray_dir, + ray.origin, + ray.direction, f32::MAX, true, QueryFilter::only_dynamic(), @@ -100,25 +103,3 @@ fn cast_ray( } } } - -// Credit to @doomy on discord. -fn ray_from_mouse_position( - window: &Window, - camera: &Camera, - camera_transform: &GlobalTransform, -) -> (Vec3, Vec3) { - let mouse_position = window.cursor_position().unwrap_or(Vec2::new(0.0, 0.0)); - - let x = 2.0 * (mouse_position.x / window.width() as f32) - 1.0; - let y = 2.0 * (mouse_position.y / window.height() as f32) - 1.0; - - let camera_inverse_matrix = - camera_transform.compute_matrix() * camera.projection_matrix().inverse(); - let near = camera_inverse_matrix * Vec3::new(x, y, -1.0).extend(1.0); - let far = camera_inverse_matrix * Vec3::new(x, y, 1.0).extend(1.0); - - let near = near.truncate() / near.w; - let far = far.truncate() / far.w; - let dir: Vec3 = far - near; - (near, dir) -} diff --git a/src/pipeline/events.rs b/src/pipeline/events.rs index 61678579..9293a13c 100644 --- a/src/pipeline/events.rs +++ b/src/pipeline/events.rs @@ -49,8 +49,8 @@ pub(crate) struct EventQueue<'a> { // Used ot retrieve the entity of colliders that have been removed from the simulation // since the last physics step. pub deleted_colliders: &'a HashMap, - pub collision_events: RwLock>, - pub contact_force_events: RwLock>, + pub collision_events: RwLock>, + pub contact_force_events: RwLock>, } impl<'a> EventQueue<'a> { diff --git a/src/pipeline/physics_hooks.rs b/src/pipeline/physics_hooks.rs index 2ce9e30b..89ae0327 100644 --- a/src/pipeline/physics_hooks.rs +++ b/src/pipeline/physics_hooks.rs @@ -1,7 +1,4 @@ -use bevy::{ - ecs::system::{SystemParam, SystemParamFetch, SystemParamItem}, - prelude::*, -}; +use bevy::{ecs::system::SystemParam, prelude::*}; use rapier::{ pipeline::{ContactModificationContext, PairFilterContext}, prelude::{PhysicsHooks, SolverFlags}, @@ -168,7 +165,7 @@ pub trait BevyPhysicsHooks: SystemParam + Send + Sync { impl BevyPhysicsHooks for T where T: 'static + PhysicsHooks + SystemParam + Send + Sync, - for<'w, 's> T::Fetch: SystemParamFetch<'w, 's, Item = T>, + for<'w, 's> T: SystemParam = T>, { fn filter_contact_pair(&self, context: PairFilterContextView) -> Option { PhysicsHooks::filter_contact_pair(self, context.raw) @@ -184,28 +181,25 @@ where } /// Adapts a type implementing `BevyPhysicsHooks` so that it implements `PhysicsHooks`. -pub(crate) struct BevyPhysicsHooksAdapter<'w, 's, Hooks> +pub(crate) struct BevyPhysicsHooksAdapter where - Hooks: 'static + BevyPhysicsHooks, - for<'w1, 's1> SystemParamItem<'w1, 's1, Hooks>: BevyPhysicsHooks, + Hooks: BevyPhysicsHooks, { - hooks: SystemParamItem<'w, 's, Hooks>, + hooks: Hooks, } -impl<'w, 's, Hooks> BevyPhysicsHooksAdapter<'w, 's, Hooks> +impl BevyPhysicsHooksAdapter where - Hooks: 'static + BevyPhysicsHooks, - for<'w1, 's1> SystemParamItem<'w1, 's1, Hooks>: BevyPhysicsHooks, + Hooks: BevyPhysicsHooks, { - pub(crate) fn new(hooks: SystemParamItem<'w, 's, Hooks>) -> Self { + pub(crate) fn new(hooks: Hooks) -> Self { Self { hooks } } } -impl<'w, 's, Hooks> PhysicsHooks for BevyPhysicsHooksAdapter<'w, 's, Hooks> +impl PhysicsHooks for BevyPhysicsHooksAdapter where - Hooks: 'static + BevyPhysicsHooks, - for<'w1, 's1> SystemParamItem<'w1, 's1, Hooks>: BevyPhysicsHooks, + Hooks: BevyPhysicsHooks, { fn filter_contact_pair(&self, context: &PairFilterContext) -> Option { let context_view = PairFilterContextView { raw: context }; diff --git a/src/plugin/mod.rs b/src/plugin/mod.rs index d832673b..fbbb9e7d 100644 --- a/src/plugin/mod.rs +++ b/src/plugin/mod.rs @@ -1,6 +1,6 @@ pub use self::configuration::{RapierConfiguration, SimulationToRenderTime, TimestepMode}; pub use self::context::RapierContext; -pub use self::plugin::{NoUserData, PhysicsStages, RapierPhysicsPlugin}; +pub use self::plugin::{NoUserData, PhysicsSet, RapierPhysicsPlugin, RapierTransformPropagateSet}; #[allow(clippy::type_complexity)] #[allow(clippy::too_many_arguments)] diff --git a/src/plugin/plugin.rs b/src/plugin/plugin.rs index 93d1714d..b9ce828d 100644 --- a/src/plugin/plugin.rs +++ b/src/plugin/plugin.rs @@ -2,8 +2,7 @@ use crate::pipeline::{CollisionEvent, ContactForceEvent}; use crate::plugin::configuration::SimulationToRenderTime; use crate::plugin::{systems, RapierConfiguration, RapierContext}; use crate::prelude::*; -use bevy::ecs::event::Events; -use bevy::ecs::system::SystemParamItem; +use bevy::ecs::{event::Events, schedule::SystemConfigs, system::SystemParamItem}; use bevy::prelude::*; use std::marker::PhantomData; @@ -59,81 +58,69 @@ where /// Provided for use when staging systems outside of this plugin using /// [`with_system_setup(false)`](Self::with_system_setup). - /// See [`PhysicsStages`] for a description of these systems. - pub fn get_systems(stage: PhysicsStages) -> SystemSet { - match stage { - PhysicsStages::SyncBackend => { - let systems = SystemSet::new() - .with_system(systems::update_character_controls) // Run the character controller before the manual transform propagation. - .with_system( - bevy::transform::transform_propagate_system - .after(systems::update_character_controls), - ) // Run Bevy transform propagation additionally to sync [`GlobalTransform`] - .with_system( - systems::init_async_colliders - .after(bevy::transform::transform_propagate_system), - ) - .with_system(systems::apply_scale.after(systems::init_async_colliders)) - .with_system(systems::apply_collider_user_changes.after(systems::apply_scale)) - .with_system( - systems::apply_rigid_body_user_changes - .after(systems::apply_collider_user_changes), - ) - .with_system( - systems::apply_joint_user_changes - .after(systems::apply_rigid_body_user_changes), - ) - .with_system( - systems::init_rigid_bodies.after(systems::apply_joint_user_changes), - ) - .with_system( - systems::init_colliders - .after(systems::init_rigid_bodies) - .after(systems::init_async_colliders), - ) - .with_system(systems::init_joints.after(systems::init_colliders)) - .with_system( - systems::apply_initial_rigid_body_impulses.after(systems::init_colliders), - ) - .with_system( - systems::sync_removals - .after(systems::init_joints) - .after(systems::apply_initial_rigid_body_impulses), - ); + /// See [`PhysicsSet`] for a description of these systems. + pub fn get_systems(set: PhysicsSet) -> SystemConfigs { + // A set for `propagate_transforms` to mark it as ambiguous with `sync_simple_transforms`. + // Used instead of the `SystemTypeSet` as that would not allow multiple instances of the system. + #[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] + struct PropagateTransformsSet; + match set { + PhysicsSet::SyncBackend => ( + // Run the character controller before the manual transform propagation. + systems::update_character_controls, + // Run Bevy transform propagation additionally to sync [`GlobalTransform`] + bevy::transform::systems::sync_simple_transforms + .in_set(RapierTransformPropagateSet) + .after(systems::update_character_controls), + bevy::transform::systems::propagate_transforms + .after(systems::update_character_controls) + .in_set(PropagateTransformsSet) + .in_set(RapierTransformPropagateSet), + systems::init_async_colliders.after(RapierTransformPropagateSet), + systems::apply_scale.after(systems::init_async_colliders), + systems::apply_collider_user_changes.after(systems::apply_scale), + systems::apply_rigid_body_user_changes.after(systems::apply_collider_user_changes), + systems::apply_joint_user_changes.after(systems::apply_rigid_body_user_changes), + systems::init_rigid_bodies.after(systems::apply_joint_user_changes), + systems::init_colliders + .after(systems::init_rigid_bodies) + .after(systems::init_async_colliders), + systems::init_joints.after(systems::init_colliders), + systems::apply_initial_rigid_body_impulses.after(systems::init_colliders), + systems::sync_removals + .after(systems::init_joints) + .after(systems::apply_initial_rigid_body_impulses), #[cfg(all(feature = "dim3", feature = "async-collider"))] - { - systems.with_system( - systems::init_async_scene_colliders.before(systems::init_async_colliders), - ) - } - #[cfg(not(feature = "dim3"))] - { - systems - } - #[cfg(feature = "headless")] - { - systems - } - } - PhysicsStages::StepSimulation => SystemSet::new() - .with_system(systems::step_simulation::) - .with_system( - Events::::update_system - .before(systems::step_simulation::), - ) - .with_system( - Events::::update_system - .before(systems::step_simulation::), - ), - PhysicsStages::Writeback => SystemSet::new() - .with_system(systems::update_colliding_entities) - .with_system(systems::writeback_rigid_bodies), - PhysicsStages::DetectDespawn => SystemSet::new().with_system(systems::sync_removals), + systems::init_async_scene_colliders + .after(bevy::scene::scene_spawner_system) + .before(systems::init_async_colliders), + ) + .into_configs(), + PhysicsSet::SyncBackendFlush => (apply_system_buffers,).into_configs(), + PhysicsSet::StepSimulation => ( + systems::step_simulation::, + Events::::update_system + .before(systems::step_simulation::), + Events::::update_system + .before(systems::step_simulation::), + ) + .into_configs(), + PhysicsSet::Writeback => ( + systems::update_colliding_entities, + systems::writeback_rigid_bodies, + ) + .into_configs(), } } } +/// A set for rapier's copy of Bevy's transform propagation systems. +/// +/// See [`TransformSystem`](bevy::transform::TransformSystem::TransformPropagate). +#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)] +pub struct RapierTransformPropagateSet; + impl Default for RapierPhysicsPlugin { fn default() -> Self { Self { @@ -144,28 +131,26 @@ impl Default for RapierPhysicsPlugin Plugin for RapierPhysicsPlugin @@ -198,9 +183,7 @@ where // Insert all of our required resources. Don’t overwrite // the `RapierConfiguration` if it already exists. - if app.world.get_resource::().is_none() { - app.insert_resource(RapierConfiguration::default()); - } + app.init_resource::(); app.insert_resource(SimulationToRenderTime::default()) .insert_resource(RapierContext { @@ -210,33 +193,33 @@ where .insert_resource(Events::::default()) .insert_resource(Events::::default()); - // Add each stage as necessary + // Add each set as necessary if self.default_system_setup { - app.add_stage_after( - CoreStage::Update, - PhysicsStages::SyncBackend, - SystemStage::parallel() - .with_system_set(Self::get_systems(PhysicsStages::SyncBackend)), + app.configure_sets( + ( + PhysicsSet::SyncBackend, + PhysicsSet::SyncBackendFlush, + PhysicsSet::StepSimulation, + PhysicsSet::Writeback, + ) + .chain() + .after(CoreSet::UpdateFlush) + .before(CoreSet::PostUpdate), + ); + + app.add_systems( + Self::get_systems(PhysicsSet::SyncBackend).in_base_set(PhysicsSet::SyncBackend), ); - app.add_stage_after( - PhysicsStages::SyncBackend, - PhysicsStages::StepSimulation, - SystemStage::parallel() - .with_system_set(Self::get_systems(PhysicsStages::StepSimulation)), + app.add_systems( + Self::get_systems(PhysicsSet::SyncBackendFlush) + .in_base_set(PhysicsSet::SyncBackendFlush), ); - app.add_stage_after( - PhysicsStages::StepSimulation, - PhysicsStages::Writeback, - SystemStage::parallel() - .with_system_set(Self::get_systems(PhysicsStages::Writeback)), + app.add_systems( + Self::get_systems(PhysicsSet::StepSimulation) + .in_base_set(PhysicsSet::StepSimulation), ); - - // NOTE: we run sync_removals at the end of the frame, too, in order to make sure we don’t miss any `RemovedComponents`. - app.add_stage_before( - CoreStage::Last, - PhysicsStages::DetectDespawn, - SystemStage::parallel() - .with_system_set(Self::get_systems(PhysicsStages::DetectDespawn)), + app.add_systems( + Self::get_systems(PhysicsSet::Writeback).in_base_set(PhysicsSet::Writeback), ); } } diff --git a/src/plugin/systems.rs b/src/plugin/systems.rs index c11ba7e7..22155bba 100644 --- a/src/plugin/systems.rs +++ b/src/plugin/systems.rs @@ -19,7 +19,7 @@ use crate::prelude::{ KinematicCharacterControllerOutput, RigidBodyDisabled, }; use crate::utils; -use bevy::ecs::system::SystemParamItem; +use bevy::ecs::system::{StaticSystemParam, SystemParamItem}; use bevy::prelude::*; use rapier::prelude::*; use std::collections::HashMap; @@ -628,20 +628,21 @@ pub fn writeback_rigid_bodies( /// System responsible for advancing the physics simulation, and updating the internal state /// for scene queries. -pub fn step_simulation( +pub fn step_simulation( mut context: ResMut, config: Res, - hooks: SystemParamItem, - (time, mut sim_to_render_time): (Res