Skip to content

Commit 9a785f2

Browse files
kristoff3rmockersf
authored andcommitted
Fix PickingInteraction change detection (#19488)
# Objective Fixes #19464 ## Solution Instead of clearing previous `PickingInteractions` before updating, we clear them last for those components that weren't updated, and use `set_if_neq` when writing. ## Testing I tried the sprite_picking example and it still works. You can add the following system to picking examples to check that change detection works as intended: ```rust fn print_picking(query: Query<(Entity, &PickingInteraction), Changed<PickingInteraction>>) { for (entity, interaction) in &query { println!("{entity} {interaction:?}"); } } ```
1 parent b46fc85 commit 9a785f2

File tree

1 file changed

+18
-14
lines changed

1 file changed

+18
-14
lines changed

crates/bevy_picking/src/hover.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -208,18 +208,6 @@ pub fn update_interactions(
208208
mut pointers: Query<(&PointerId, &PointerPress, &mut PointerInteraction)>,
209209
mut interact: Query<&mut PickingInteraction>,
210210
) {
211-
// Clear all previous hover data from pointers and entities
212-
for (pointer, _, mut pointer_interaction) in &mut pointers {
213-
pointer_interaction.sorted_entities.clear();
214-
if let Some(previously_hovered_entities) = previous_hover_map.get(pointer) {
215-
for entity in previously_hovered_entities.keys() {
216-
if let Ok(mut interaction) = interact.get_mut(*entity) {
217-
*interaction = PickingInteraction::None;
218-
}
219-
}
220-
}
221-
}
222-
223211
// Create a map to hold the aggregated interaction for each entity. This is needed because we
224212
// need to be able to insert the interaction component on entities if they do not exist. To do
225213
// so we need to know the final aggregated interaction state to avoid the scenario where we set
@@ -239,13 +227,29 @@ pub fn update_interactions(
239227
}
240228

241229
// Take the aggregated entity states and update or insert the component if missing.
242-
for (hovered_entity, new_interaction) in new_interaction_state.drain() {
230+
for (&hovered_entity, &new_interaction) in new_interaction_state.iter() {
243231
if let Ok(mut interaction) = interact.get_mut(hovered_entity) {
244-
*interaction = new_interaction;
232+
interaction.set_if_neq(new_interaction);
245233
} else if let Ok(mut entity_commands) = commands.get_entity(hovered_entity) {
246234
entity_commands.try_insert(new_interaction);
247235
}
248236
}
237+
238+
// Clear all previous hover data from pointers that are no longer hovering any entities.
239+
// We do this last to preserve change detection for picking interactions.
240+
for (pointer, _, _) in &mut pointers {
241+
let Some(previously_hovered_entities) = previous_hover_map.get(pointer) else {
242+
continue;
243+
};
244+
245+
for entity in previously_hovered_entities.keys() {
246+
if !new_interaction_state.contains_key(entity) {
247+
if let Ok(mut interaction) = interact.get_mut(*entity) {
248+
interaction.set_if_neq(PickingInteraction::None);
249+
}
250+
}
251+
}
252+
}
249253
}
250254

251255
/// Merge the interaction state of this entity into the aggregated map.

0 commit comments

Comments
 (0)