use bevy_app::{EventReader, Events}; use bevy_ecs::{Local, Res, ResMut}; use bevy_math::Vec2; use bevy_utils::{HashMap, HashSet}; /// A touch input event #[derive(Debug, Clone)] pub struct TouchInput { pub phase: TouchPhase, pub position: Vec2, /// /// ## Platform-specific /// /// Unique identifier of a finger. pub id: u64, } /// Describes touch-screen input state. #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub enum TouchPhase { Started, Moved, Ended, Cancelled, } #[derive(Default)] pub struct TouchSystemState { touch_event_reader: EventReader, } #[derive(Debug, Clone)] pub struct Touch { pub id: u64, pub start_position: Vec2, pub previous_position: Vec2, pub position: Vec2, } impl Touch { pub fn delta(&self) -> Vec2 { self.position - self.previous_position } pub fn distance(&self) -> Vec2 { self.position - self.start_position } } #[derive(Default)] pub struct Touches { active_touches: HashMap, just_pressed: HashSet, just_released: HashSet, just_cancelled: HashSet, } impl Touches { pub fn iter(&self) -> impl Iterator + '_ { self.active_touches.values() } pub fn just_pressed(&self, id: u64) -> bool { self.just_pressed.contains(&id) } pub fn iter_just_pressed(&self) -> impl Iterator + '_ { self.just_pressed .iter() .map(move |id| self.active_touches.get(id).unwrap()) } pub fn just_released(&self, id: u64) -> bool { self.just_released.contains(&id) } pub fn iter_just_released(&self) -> impl Iterator + '_ { self.just_released .iter() .map(move |id| self.active_touches.get(id).unwrap()) } pub fn just_cancelled(&self, id: u64) -> bool { self.just_cancelled.contains(&id) } pub fn iter_just_cancelled(&self) -> impl Iterator + '_ { self.just_cancelled .iter() .map(move |id| self.active_touches.get(id).unwrap()) } } /// Updates the Touches resource with the latest TouchInput events pub fn touch_screen_input_system( mut state: Local, mut touch_state: ResMut, touch_input_events: Res>, ) { let touch_state = &mut *touch_state; for released_id in touch_state.just_released.iter() { touch_state.active_touches.remove(&released_id); } for cancelled_id in touch_state.just_cancelled.iter() { touch_state.active_touches.remove(&cancelled_id); } touch_state.just_pressed.clear(); touch_state.just_cancelled.clear(); for event in state.touch_event_reader.iter(&touch_input_events) { let active_touch = touch_state.active_touches.get(&event.id); match event.phase { TouchPhase::Started => { touch_state.active_touches.insert( event.id, Touch { id: event.id, start_position: event.position, previous_position: event.position, position: event.position, }, ); touch_state.just_pressed.insert(event.id); } TouchPhase::Moved => { let old_touch = active_touch.unwrap(); let mut new_touch = old_touch.clone(); new_touch.previous_position = new_touch.position; new_touch.position = event.position; touch_state.active_touches.insert(event.id, new_touch); } TouchPhase::Ended => { touch_state.just_released.insert(event.id); } TouchPhase::Cancelled => { touch_state.just_cancelled.insert(event.id); } }; } }