From aa477028ef4b234217565f751048f8021225cfc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9sar=20Sagaert?= Date: Mon, 1 Apr 2024 23:45:47 +0200 Subject: [PATCH] fix previous_position / previous_force being discarded too early (#12556) # Objective Fixes #12442 ## Solution Change `process_touch_event` to not update previous_position / previous_force, and change it once per frame in `touch_screen_input_system`. --- crates/bevy_input/src/touch.rs | 79 ++++++++++++++++++++++++++++++++-- 1 file changed, 75 insertions(+), 4 deletions(-) diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index d1f357ed57..2344a04623 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -373,8 +373,9 @@ impl Touches { } TouchPhase::Moved => { if let Some(mut new_touch) = self.pressed.get(&event.id).cloned() { - new_touch.previous_position = new_touch.position; - new_touch.previous_force = new_touch.force; + // NOTE: This does not update the previous_force / previous_position field; + // they should be updated once per frame, not once per event + // See https://github.com/bevyengine/bevy/issues/12442 new_touch.position = event.position; new_touch.force = event.force; self.pressed.insert(event.id, new_touch); @@ -427,8 +428,15 @@ pub fn touch_screen_input_system( touch_state.just_canceled.clear(); } - for event in touch_input_events.read() { - touch_state.process_touch_event(event); + if !touch_input_events.is_empty() { + for touch in touch_state.pressed.values_mut() { + touch.previous_position = touch.position; + touch.previous_force = touch.force; + } + + for event in touch_input_events.read() { + touch_state.process_touch_event(event); + } } } @@ -551,6 +559,69 @@ mod test { assert_ne!(touch.previous_position, touch.position); } + // See https://github.com/bevyengine/bevy/issues/12442 + #[test] + fn touch_process_multi_event() { + use crate::{touch::TouchPhase, TouchInput, Touches}; + use bevy_ecs::entity::Entity; + use bevy_math::Vec2; + + let mut touches = Touches::default(); + + let started_touch_event = TouchInput { + phase: TouchPhase::Started, + position: Vec2::splat(4.0), + window: Entity::PLACEHOLDER, + force: None, + id: 4, + }; + + let moved_touch_event1 = TouchInput { + phase: TouchPhase::Moved, + position: Vec2::splat(5.0), + window: Entity::PLACEHOLDER, + force: None, + id: started_touch_event.id, + }; + + let moved_touch_event2 = TouchInput { + phase: TouchPhase::Moved, + position: Vec2::splat(6.0), + window: Entity::PLACEHOLDER, + force: None, + id: started_touch_event.id, + }; + + // tick 1: touch is started during frame + for touch in touches.pressed.values_mut() { + // update ONCE, at start of frame + touch.previous_position = touch.position; + } + touches.process_touch_event(&started_touch_event); + touches.process_touch_event(&moved_touch_event1); + touches.process_touch_event(&moved_touch_event2); + + { + let touch = touches.get_pressed(started_touch_event.id).unwrap(); + assert_eq!(touch.previous_position, started_touch_event.position); + assert_eq!(touch.position, moved_touch_event2.position); + } + + // tick 2: touch was started before frame + for touch in touches.pressed.values_mut() { + touch.previous_position = touch.position; + } + touches.process_touch_event(&moved_touch_event1); + touches.process_touch_event(&moved_touch_event2); + touches.process_touch_event(&moved_touch_event1); + + { + let touch = touches.get_pressed(started_touch_event.id).unwrap(); + assert_eq!(touch.previous_position, moved_touch_event2.position); + assert_eq!(touch.position, moved_touch_event1.position); + } + } + #[test] fn touch_pressed() { use crate::{touch::TouchPhase, TouchInput, Touches};