Skip to content

Commit

Permalink
Touch support implementation
Browse files Browse the repository at this point in the history
Adds a basic touch input system

Co-authored-by: Michael Hills <mhills@gmail.com>
  • Loading branch information
naithar and MichaelHills committed Oct 17, 2020
1 parent d004bce commit 4023bc0
Show file tree
Hide file tree
Showing 7 changed files with 175 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Unreleased

### Added
- [Touch Input][]
- [Do not depend on spirv on wasm32 target][689]
- [Another fast compile flag for macOS][552]

Expand All @@ -15,6 +16,7 @@
- Individual color-components must now be accessed through setters and getters: `.r`, `.g`, `.b`, `.a`, `.set_r`, `.set_g`, `.set_b`, `.set_a`, and the corresponding methods with the `*_linear` suffix.
- Despawning an entity multiple times causes a debug-level log message to be emitted instead of a panic [649] [651]

[]:
[689]: https://github.com/bevyengine/bevy/pull/689
[552]: https://github.com/bevyengine/bevy/pull/552
[616]: https://github.com/bevyengine/bevy/pull/616
Expand Down
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ path = "examples/input/keyboard_input_events.rs"
name = "gamepad_input"
path = "examples/input/gamepad_input.rs"

[[example]]
name = "touch_input"
path = "examples/input/touch_input.rs"

[[example]]
name = "scene"
path = "examples/scene/scene.rs"
Expand Down
10 changes: 9 additions & 1 deletion crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod input;
pub mod keyboard;
pub mod mouse;
pub mod system;
pub mod touch;

pub use axis::*;
pub use input::*;
Expand All @@ -23,6 +24,7 @@ pub mod prelude {
use bevy_app::prelude::*;
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
use touch::{touch_screen_input_system, TouchInput, TouchInputState};

use bevy_ecs::IntoQuerySystem;
use gamepad::{GamepadAxis, GamepadButton, GamepadEvent};
Expand Down Expand Up @@ -50,6 +52,12 @@ impl Plugin for InputPlugin {
.add_event::<GamepadEvent>()
.init_resource::<Input<GamepadButton>>()
.init_resource::<Axis<GamepadAxis>>()
.init_resource::<Axis<GamepadButton>>();
.init_resource::<Axis<GamepadButton>>()
.add_event::<TouchInput>()
.init_resource::<TouchInputState>()
.add_system_to_stage(
bevy_app::stage::EVENT_UPDATE,
touch_screen_input_system.system(),
);
}
}
99 changes: 99 additions & 0 deletions crates/bevy_input/src/touch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use bevy_app::{EventReader, Events};
use bevy_ecs::{Local, Res, ResMut};
use bevy_math::Vec2;
use std::collections::{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<TouchInput>,
}

#[derive(Debug, Clone)]
pub struct ActiveTouch {
start_position: Vec2,
previous_position: Vec2,
current_position: Vec2,
}

impl ActiveTouch {
pub fn delta(&self) -> Vec2 {
self.current_position - self.previous_position
}

pub fn distance(&self) -> Vec2 {
self.current_position - self.start_position
}
}

#[derive(Default)]
pub struct TouchInputState {
pub active_touches: HashMap<u64, ActiveTouch>,
pub just_pressed: HashSet<u64>,
pub just_released: HashSet<u64>,
pub just_cancelled: HashSet<u64>,
}

/// Updates the TouchInputState resource with the latest TouchInput events
pub fn touch_screen_input_system(
mut state: Local<TouchSystemState>,
mut touch_state: ResMut<TouchInputState>,
touch_input_events: Res<Events<TouchInput>>,
) {
touch_state.just_pressed.clear();
touch_state.just_released.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,
ActiveTouch {
start_position: event.position,
previous_position: event.position,
current_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.current_position;
new_touch.current_position = event.position;
touch_state.active_touches.insert(event.id, new_touch);
}
TouchPhase::Ended => {
touch_state.active_touches.remove(&event.id);
touch_state.just_released.insert(event.id);
}
TouchPhase::Cancelled => {
touch_state.active_touches.remove(&event.id);
touch_state.just_cancelled.insert(event.id);
}
};
}
}
15 changes: 15 additions & 0 deletions crates/bevy_winit/src/converters.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use bevy_input::{
keyboard::{ElementState, KeyCode, KeyboardInput},
mouse::MouseButton,
touch::{TouchInput, TouchPhase},
};
use bevy_math::Vec2;

pub fn convert_keyboard_input(keyboard_input: &winit::event::KeyboardInput) -> KeyboardInput {
KeyboardInput {
Expand All @@ -27,6 +29,19 @@ pub fn convert_mouse_button(mouse_button: winit::event::MouseButton) -> MouseBut
}
}

pub fn convert_touch_input(touch_input: winit::event::Touch) -> TouchInput {
TouchInput {
phase: match touch_input.phase {
winit::event::TouchPhase::Started => TouchPhase::Started,
winit::event::TouchPhase::Moved => TouchPhase::Moved,
winit::event::TouchPhase::Ended => TouchPhase::Ended,
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
},
position: Vec2::new(touch_input.location.x as f32, touch_input.location.y as f32),
id: touch_input.id,
}
}

pub fn convert_virtual_key_code(virtual_key_code: winit::event::VirtualKeyCode) -> KeyCode {
match virtual_key_code {
winit::event::VirtualKeyCode::Key1 => KeyCode::Key1,
Expand Down
6 changes: 6 additions & 0 deletions crates/bevy_winit/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod winit_windows;
use bevy_input::{
keyboard::KeyboardInput,
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
touch::TouchInput,
};
pub use winit_config::*;
pub use winit_windows::*;
Expand Down Expand Up @@ -258,6 +259,11 @@ pub fn winit_runner(mut app: App) {
});
}
},
WindowEvent::Touch(touch) => {
let mut touch_input_events =
app.resources.get_mut::<Events<TouchInput>>().unwrap();
touch_input_events.send(converters::convert_touch_input(touch));
}
_ => {}
},
event::Event::DeviceEvent { ref event, .. } => {
Expand Down
40 changes: 40 additions & 0 deletions examples/input/touch_input.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
use bevy::{input::touch::*, prelude::*};

fn main() {
App::build()
.add_default_plugins()
.init_resource::<TouchHandlerState>()
.add_system(touch_system.system())
.run();
}

#[derive(Default)]
struct TouchHandlerState {
touch_event_reader: EventReader<TouchInput>,
}

fn touch_system(
mut state: ResMut<TouchHandlerState>,
touch_events: Res<Events<TouchInput>>,
touch_input_state: Res<TouchInputState>,
) {
for event in state.touch_event_reader.iter(&touch_events) {
if touch_input_state.just_pressed.contains(&event.id) {
println!(
"just pressed touch with id: {:?}, at: {:?}",
event.id, event.position
);
}

if touch_input_state.just_released.contains(&event.id) {
println!(
"just released touch with id: {:?}, at: {:?}",
event.id, event.position
);
}

if touch_input_state.just_cancelled.contains(&event.id) {
println!("cancelled touch with id: {:?}", event.id);
}
}
}

0 comments on commit 4023bc0

Please sign in to comment.