|
| 1 | +use bevy_app::{EventReader, Events}; |
| 2 | +use bevy_ecs::{Local, Res, ResMut}; |
| 3 | +use bevy_math::Vec2; |
| 4 | +use std::collections::{HashMap, HashSet}; |
| 5 | + |
| 6 | +/// A touch input event |
| 7 | +#[derive(Debug, Clone)] |
| 8 | +pub struct TouchInput { |
| 9 | + pub phase: TouchPhase, |
| 10 | + pub position: Vec2, |
| 11 | + /// |
| 12 | + /// ## Platform-specific |
| 13 | + /// |
| 14 | + /// Unique identifier of a finger. |
| 15 | + pub id: u64, |
| 16 | +} |
| 17 | + |
| 18 | +/// Describes touch-screen input state. |
| 19 | +#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] |
| 20 | +#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] |
| 21 | +pub enum TouchPhase { |
| 22 | + Started, |
| 23 | + Moved, |
| 24 | + Ended, |
| 25 | + Cancelled, |
| 26 | +} |
| 27 | + |
| 28 | +#[derive(Default)] |
| 29 | +pub struct TouchSystemState { |
| 30 | + touch_event_reader: EventReader<TouchInput>, |
| 31 | +} |
| 32 | + |
| 33 | +#[derive(Debug, Clone)] |
| 34 | +pub struct ActiveTouch { |
| 35 | + start_position: Vec2, |
| 36 | + previous_position: Vec2, |
| 37 | + current_position: Vec2, |
| 38 | +} |
| 39 | + |
| 40 | +impl ActiveTouch { |
| 41 | + pub fn delta(&self) -> Vec2 { |
| 42 | + self.current_position - self.previous_position |
| 43 | + } |
| 44 | + |
| 45 | + pub fn distance(&self) -> Vec2 { |
| 46 | + self.current_position - self.start_position |
| 47 | + } |
| 48 | +} |
| 49 | + |
| 50 | +#[derive(Default)] |
| 51 | +pub struct TouchInputState { |
| 52 | + pub active_touches: HashMap<u64, ActiveTouch>, |
| 53 | + pub just_pressed: HashSet<u64>, |
| 54 | + pub just_released: HashSet<u64>, |
| 55 | + pub just_cancelled: HashSet<u64>, |
| 56 | +} |
| 57 | + |
| 58 | +/// Updates the TouchInputState resource with the latest TouchInput events |
| 59 | +pub fn touch_screen_input_system( |
| 60 | + mut state: Local<TouchSystemState>, |
| 61 | + mut touch_state: ResMut<TouchInputState>, |
| 62 | + touch_input_events: Res<Events<TouchInput>>, |
| 63 | +) { |
| 64 | + touch_state.just_pressed.clear(); |
| 65 | + touch_state.just_released.clear(); |
| 66 | + touch_state.just_cancelled.clear(); |
| 67 | + |
| 68 | + for event in state.touch_event_reader.iter(&touch_input_events) { |
| 69 | + let active_touch = touch_state.active_touches.get(&event.id); |
| 70 | + match event.phase { |
| 71 | + TouchPhase::Started => { |
| 72 | + touch_state.active_touches.insert( |
| 73 | + event.id, |
| 74 | + ActiveTouch { |
| 75 | + start_position: event.position, |
| 76 | + previous_position: event.position, |
| 77 | + current_position: event.position, |
| 78 | + }, |
| 79 | + ); |
| 80 | + touch_state.just_pressed.insert(event.id); |
| 81 | + } |
| 82 | + TouchPhase::Moved => { |
| 83 | + let old_touch = active_touch.unwrap(); |
| 84 | + let mut new_touch = old_touch.clone(); |
| 85 | + new_touch.previous_position = new_touch.current_position; |
| 86 | + new_touch.current_position = event.position; |
| 87 | + touch_state.active_touches.insert(event.id, new_touch); |
| 88 | + } |
| 89 | + TouchPhase::Ended => { |
| 90 | + touch_state.active_touches.remove(&event.id); |
| 91 | + touch_state.just_released.insert(event.id); |
| 92 | + } |
| 93 | + TouchPhase::Cancelled => { |
| 94 | + touch_state.active_touches.remove(&event.id); |
| 95 | + touch_state.just_cancelled.insert(event.id); |
| 96 | + } |
| 97 | + }; |
| 98 | + } |
| 99 | +} |
0 commit comments