diff --git a/src/collision/collider/backend.rs b/src/collision/collider/backend.rs index 0fd04e88..a573b83a 100644 --- a/src/collision/collider/backend.rs +++ b/src/collision/collider/backend.rs @@ -211,6 +211,14 @@ impl Plugin for ColliderBackendPlugin { ), ); + // Update collider parents for colliders that are on the same entity as the rigid body. + app.add_systems( + self.schedule, + update_root_collider_parents:: + .after(PrepareSet::InitColliders) + .before(PrepareSet::Finalize), + ); + let physics_schedule = app .get_schedule_mut(PhysicsSchedule) .expect("add PhysicsSchedule first"); @@ -274,6 +282,31 @@ pub(crate) fn init_colliders( } } +/// Updates [`ColliderParent`] for colliders that are on the same entity as the [`RigidBody`]. +/// +/// The [`ColliderHierarchyPlugin`] should be used to handle hierarchies. +#[allow(clippy::type_complexity)] +fn update_root_collider_parents( + mut commands: Commands, + mut bodies: Query< + (Entity, Option<&mut ColliderParent>), + (With, With, Or<(Added, Added)>), + >, +) { + for (entity, collider_parent) in &mut bodies { + if let Some(mut collider_parent) = collider_parent { + collider_parent.0 = entity; + } else { + commands.entity(entity).try_insert(( + ColliderParent(entity), + // TODO: This probably causes a one frame delay. Compute real value? + ColliderTransform::default(), + PreviousColliderTransform::default(), + )); + } + } +} + /// Generates [`Collider`]s based on [`ColliderConstructor`]s. /// /// If a [`ColliderConstructor`] requires a mesh, the system keeps running diff --git a/src/collision/collider/hierarchy.rs b/src/collision/collider/hierarchy.rs index 2fd625e6..d6beabef 100644 --- a/src/collision/collider/hierarchy.rs +++ b/src/collision/collider/hierarchy.rs @@ -117,35 +117,33 @@ impl Plugin for ColliderHierarchyPlugin { .in_set(NarrowPhaseSet::First), ); } + + fn finish(&self, app: &mut App) { + if !app.is_plugin_added::() { + warn!("`ColliderHierarchyPlugin` requires Bevy's `HierarchyPlugin` to function. If you don't need collider hierarchies, consider disabling this plugin.",); + } + } } #[derive(Reflect, Clone, Copy, Component, Debug, Default, Deref, DerefMut, PartialEq)] #[reflect(Component)] pub(crate) struct PreviousColliderTransform(pub ColliderTransform); +/// Updates [`ColliderParent`] for descendant colliders of [`RigidBody`] entities. +/// +/// The [`ColliderBackendPlugin`] handles collider parents for colliders that are +/// on the same entity as the rigid body. #[allow(clippy::type_complexity)] fn update_collider_parents( mut commands: Commands, - mut bodies: Query<(Entity, Option<&mut ColliderParent>, Has), With>, + mut bodies: Query, With>)>, children: Query<&Children>, mut child_colliders: Query< Option<&mut ColliderParent>, (With, Without), >, ) { - for (entity, collider_parent, has_collider) in &mut bodies { - if has_collider { - if let Some(mut collider_parent) = collider_parent { - collider_parent.0 = entity; - } else { - commands.entity(entity).try_insert(( - ColliderParent(entity), - // TODO: This probably causes a one frame delay. Compute real value? - ColliderTransform::default(), - PreviousColliderTransform::default(), - )); - } - } + for entity in &mut bodies { for child in children.iter_descendants(entity) { if let Ok(collider_parent) = child_colliders.get_mut(child) { if let Some(mut collider_parent) = collider_parent { diff --git a/src/sync/ancestor_marker.rs b/src/sync/ancestor_marker.rs index 4d970c2f..d3f6636f 100644 --- a/src/sync/ancestor_marker.rs +++ b/src/sync/ancestor_marker.rs @@ -78,6 +78,9 @@ impl Plugin for AncestorMarkerPlugin { }, ); + // Initialize `HierarchyEvent` in case `HierarchyPlugin` is not added. + app.add_event::(); + // Update markers when changes are made to the hierarchy. // TODO: This should be an observer. It'd remove the need for this scheduling nonsense // and make the implementation more robust. @@ -90,13 +93,6 @@ impl Plugin for AncestorMarkerPlugin { app.add_systems(self.schedule, update_markers_on_hierarchy_changes::); } } - - fn finish(&self, app: &mut App) { - assert!( - app.is_plugin_added::(), - "`AncestorMarkerPlugin` requires Bevy's `HierarchyPlugin` to function.", - ); - } } /// A marker component that marks an entity as an ancestor of an entity with the given component `C`. diff --git a/src/tests.rs b/src/tests.rs index 9b0b6974..b5b8f0f7 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -35,8 +35,9 @@ fn create_app() -> App { app.add_plugins(( MinimalPlugins, TransformPlugin, - HierarchyPlugin, - PhysicsPlugins::default(), + PhysicsPlugins::default() + .build() + .disable::(), bevy::asset::AssetPlugin::default(), #[cfg(feature = "bevy_scene")] bevy::scene::ScenePlugin, @@ -256,8 +257,9 @@ fn no_ambiguity_errors() { App::new() .add_plugins(( MinimalPlugins, - HierarchyPlugin, - PhysicsPlugins::new(DeterministicSchedule), + PhysicsPlugins::new(DeterministicSchedule) + .build() + .disable::(), bevy::asset::AssetPlugin::default(), #[cfg(feature = "bevy_scene")] bevy::scene::ScenePlugin,