diff --git a/crates/bevy_input/src/touch.rs b/crates/bevy_input/src/touch.rs index b7da9ced53..4ba55c0118 100644 --- a/crates/bevy_input/src/touch.rs +++ b/crates/bevy_input/src/touch.rs @@ -3,38 +3,45 @@ use bevy_ecs::system::ResMut; use bevy_math::Vec2; use bevy_utils::HashMap; -/// Represents a touch event +/// A touch input event. /// -/// Every time the user touches the screen, a new `Start` event with an unique -/// identifier for the finger is generated. When the finger is lifted, an `End` +/// ## Logic +/// +/// Every time the user touches the screen, a new [`TouchPhase::Started`] event with an unique +/// identifier for the finger is generated. When the finger is lifted, the [`TouchPhase::Ended`] /// event is generated with the same finger id. /// -/// After a `Start` event has been emitted, there may be zero or more `Move` +/// After a [`TouchPhase::Started`] event has been emitted, there may be zero or more [`TouchPhase::Moved`] /// events when the finger is moved or the touch pressure changes. /// -/// The finger id may be reused by the system after an `End` event. The user -/// should assume that a new `Start` event received with the same id has nothing +/// The finger id may be reused by the system after an [`TouchPhase::Ended`] event. The user +/// should assume that a new [`TouchPhase::Started`] event received with the same id has nothing /// to do with the old finger and is a new finger. /// -/// A `Cancelled` event is emitted when the system has canceled tracking this +/// A [`TouchPhase::Cancelled`] event is emitted when the system has canceled tracking this /// touch, such as when the window loses focus, or on iOS if the user moves the /// device against their face. +/// +/// ## Note +/// +/// This event is the translated version of the `WindowEvent::Touch` from the `winit` crate. +/// It is available to the end user and can be used for game logic. #[derive(Debug, Clone, Copy, PartialEq)] pub struct TouchInput { + /// The phase of the touch input. pub phase: TouchPhase, + /// The position of the finger on the touchscreen. pub position: Vec2, - /// Describes how hard the screen was pressed. May be `None` if the platform - /// does not support pressure sensitivity. + /// Describes how hard the screen was pressed. /// - /// ## Platform-specific - /// - /// - Only available on **iOS** 9.0+ and **Windows** 8+. + /// May be [`None`] if the platform does not support pressure sensitivity. + /// This feature is only available on **iOS** 9.0+ and **Windows** 8+. pub force: Option, - /// Unique identifier of a finger. + /// The unique identifier of the finger. pub id: u64, } -/// Describes the force of a touch event +/// A force description of a [`Touch`](crate::touch::Touch) input. #[derive(Debug, Clone, Copy, PartialEq)] pub enum ForceTouch { /// On iOS, the force is calibrated so that the same number corresponds to @@ -63,65 +70,107 @@ pub enum ForceTouch { /// If the platform reports the force as normalized, we have no way of /// knowing how much pressure 1.0 corresponds to – we know it's the maximum /// amount of force, but as to how much force, you might either have to - /// press really really hard, or not hard at all, depending on the device. + /// press really hard, or not hard at all, depending on the device. Normalized(f64), } -/// Describes touch-screen input state. +/// A phase of a [`TouchInput`](crate::touch::TouchInput). +/// +/// ## Usage +/// +/// It is used to describe the phase of the touch input that is currently active. +/// This includes a phase that indicates that a touch input has started or ended, +/// or that a finger has moved. There is also a cancelled phase that indicates that +/// the system cancelled the tracking of the finger. #[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] pub enum TouchPhase { + /// A finger started to touch the touchscreen. Started, + /// A finger moved over the touchscreen. Moved, + /// A finger stopped touching the touchscreen. Ended, + /// The system cancelled the tracking of the finger. + /// + /// This occurs when the window loses focus, or on iOS if the user moves the + /// device against their face. Cancelled, } +/// A touch input. +/// +/// ## Usage +/// +/// It is used to store the position and force of a touch input and also the `id` of the finger. +/// The data of the touch input comes from the [`TouchInput`] event and is being stored +/// inside of the [`Touches`] `bevy` resource. #[derive(Debug, Clone, Copy)] pub struct Touch { + /// The id of the touch input. id: u64, + /// The starting position of the touch input. start_position: Vec2, + /// The starting force of the touch input. start_force: Option, + /// The previous position of the touch input. previous_position: Vec2, + /// The previous force of the touch input. previous_force: Option, + /// The current position of the touch input. position: Vec2, + /// The current force of the touch input. force: Option, } impl Touch { + /// The delta of the current `position` and the `previous_position`. pub fn delta(&self) -> Vec2 { self.position - self.previous_position } + /// The distance of the `start_position` and the current `position`. pub fn distance(&self) -> Vec2 { self.position - self.start_position } + /// Returns the `id` of the touch. #[inline] pub fn id(&self) -> u64 { self.id } + /// Returns the `start_position` of the touch. #[inline] pub fn start_position(&self) -> Vec2 { self.start_position } + /// Returns the `start_force` of the touch. #[inline] pub fn start_force(&self) -> Option { self.start_force } + /// Returns the `previous_position` of the touch. #[inline] pub fn previous_position(&self) -> Vec2 { self.previous_position } + /// Returns the `previous_force` of the touch. + #[inline] + pub fn previous_force(&self) -> Option { + self.previous_force + } + + /// Returns the current `position` of the touch. #[inline] pub fn position(&self) -> Vec2 { self.position } + /// Returns the current `force` of the touch. #[inline] pub fn force(&self) -> Option { self.force @@ -142,51 +191,76 @@ impl From<&TouchInput> for Touch { } } +/// A collection of [`Touch`]es. +/// +/// ## Usage +/// +/// It is used to create a `bevy` resource that stores the data of the touches on a touchscreen +/// and can be accessed inside of a system. +/// +/// ## Updating +/// +/// The resource is updated inside of the [`touch_screen_input_system`](crate::touch::touch_screen_input_system). #[derive(Debug, Clone, Default)] pub struct Touches { + /// A collection of every [`Touch`] that is currently being pressed. pressed: HashMap, + /// A collection of every [`Touch`] that just got pressed. just_pressed: HashMap, + /// A collection of every [`Touch`] that just got released. just_released: HashMap, + /// A collection of every [`Touch`] that just got cancelled. just_cancelled: HashMap, } impl Touches { + /// An iterator visiting every pressed [`Touch`] input in arbitrary order. pub fn iter(&self) -> impl Iterator + '_ { self.pressed.values() } + /// Returns the [`Touch`] input corresponding to the `id` if it is being pressed. pub fn get_pressed(&self, id: u64) -> Option<&Touch> { self.pressed.get(&id) } + /// Returns `true` if the input corresponding to the `id` has just been pressed. pub fn just_pressed(&self, id: u64) -> bool { self.just_pressed.contains_key(&id) } + /// An iterator visiting every just pressed [`Touch`] input in arbitrary order. pub fn iter_just_pressed(&self) -> impl Iterator { self.just_pressed.values() } + /// Returns the [`Touch`] input corresponding to the `id` if it has just been released. pub fn get_released(&self, id: u64) -> Option<&Touch> { self.just_released.get(&id) } + /// Returns `true` if the input corresponding to the `id` has just been released. pub fn just_released(&self, id: u64) -> bool { self.just_released.contains_key(&id) } + /// An iterator visiting every just released [`Touch`] input in arbitrary order. pub fn iter_just_released(&self) -> impl Iterator { self.just_released.values() } + /// Returns `true` if the input corresponding to the `id` has just been cancelled. pub fn just_cancelled(&self, id: u64) -> bool { self.just_cancelled.contains_key(&id) } + /// An iterator visiting every just cancelled [`Touch`] input in arbitrary order. pub fn iter_just_cancelled(&self) -> impl Iterator { self.just_cancelled.values() } + /// Processes a [`TouchInput`] event by updating the `pressed`, `just_pressed`, + /// `just_released`, and `just_cancelled` collections. fn process_touch_event(&mut self, event: &TouchInput) { match event.phase { TouchPhase::Started => { @@ -213,6 +287,13 @@ impl Touches { }; } + /// Clears the `just_pressed`, `just_released`, and `just_cancelled` collections. + /// + /// This is not clearing the `pressed` collection, because it could incorrectly mark + /// a touch input as not pressed eventhough it is pressed. This could happen if the + /// touch input is not moving for a single frame and would therefore be marked as + /// not pressed, because this function is called on every single frame no matter + /// if there was an event or not. fn update(&mut self) { self.just_pressed.clear(); self.just_released.clear(); @@ -220,7 +301,12 @@ impl Touches { } } -/// Updates the `Touches` resource with the latest `TouchInput` events +/// Updates the [`Touches`] resource with the latest [`TouchInput`] events. +/// +/// ## Differences +/// +/// The main difference between the [`TouchInput`] event and the [`Touches`] resource is that +/// the latter has convenient functions like [`Touches::just_pressed`] and [`Touches::just_released`]. pub fn touch_screen_input_system( mut touch_state: ResMut, mut touch_input_events: EventReader,