Skip to content

Commit ecc938f

Browse files
naitharMichaelHills
andcommitted
Touch support implementation
Adds a basic touch input system Co-authored-by: Michael Hills <[email protected]>
1 parent d004bce commit ecc938f

File tree

7 files changed

+175
-1
lines changed

7 files changed

+175
-1
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## Unreleased
44

55
### Added
6+
- [Touch Input][696]
67
- [Do not depend on spirv on wasm32 target][689]
78
- [Another fast compile flag for macOS][552]
89

@@ -15,6 +16,7 @@
1516
- 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.
1617
- Despawning an entity multiple times causes a debug-level log message to be emitted instead of a panic [649] [651]
1718

19+
[696]: https://github.com/bevyengine/bevy/pull/696
1820
[689]: https://github.com/bevyengine/bevy/pull/689
1921
[552]: https://github.com/bevyengine/bevy/pull/552
2022
[616]: https://github.com/bevyengine/bevy/pull/616

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@ path = "examples/input/keyboard_input_events.rs"
230230
name = "gamepad_input"
231231
path = "examples/input/gamepad_input.rs"
232232

233+
[[example]]
234+
name = "touch_input"
235+
path = "examples/input/touch_input.rs"
236+
233237
[[example]]
234238
name = "scene"
235239
path = "examples/scene/scene.rs"

crates/bevy_input/src/lib.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod input;
44
pub mod keyboard;
55
pub mod mouse;
66
pub mod system;
7+
pub mod touch;
78

89
pub use axis::*;
910
pub use input::*;
@@ -23,6 +24,7 @@ pub mod prelude {
2324
use bevy_app::prelude::*;
2425
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
2526
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
27+
use touch::{touch_screen_input_system, TouchInput, TouchInputState};
2628

2729
use bevy_ecs::IntoQuerySystem;
2830
use gamepad::{GamepadAxis, GamepadButton, GamepadEvent};
@@ -50,6 +52,12 @@ impl Plugin for InputPlugin {
5052
.add_event::<GamepadEvent>()
5153
.init_resource::<Input<GamepadButton>>()
5254
.init_resource::<Axis<GamepadAxis>>()
53-
.init_resource::<Axis<GamepadButton>>();
55+
.init_resource::<Axis<GamepadButton>>()
56+
.add_event::<TouchInput>()
57+
.init_resource::<TouchInputState>()
58+
.add_system_to_stage(
59+
bevy_app::stage::EVENT_UPDATE,
60+
touch_screen_input_system.system(),
61+
);
5462
}
5563
}

crates/bevy_input/src/touch.rs

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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+
}

crates/bevy_winit/src/converters.rs

+15
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
use bevy_input::{
22
keyboard::{ElementState, KeyCode, KeyboardInput},
33
mouse::MouseButton,
4+
touch::{TouchInput, TouchPhase},
45
};
6+
use bevy_math::Vec2;
57

68
pub fn convert_keyboard_input(keyboard_input: &winit::event::KeyboardInput) -> KeyboardInput {
79
KeyboardInput {
@@ -27,6 +29,19 @@ pub fn convert_mouse_button(mouse_button: winit::event::MouseButton) -> MouseBut
2729
}
2830
}
2931

32+
pub fn convert_touch_input(touch_input: winit::event::Touch) -> TouchInput {
33+
TouchInput {
34+
phase: match touch_input.phase {
35+
winit::event::TouchPhase::Started => TouchPhase::Started,
36+
winit::event::TouchPhase::Moved => TouchPhase::Moved,
37+
winit::event::TouchPhase::Ended => TouchPhase::Ended,
38+
winit::event::TouchPhase::Cancelled => TouchPhase::Cancelled,
39+
},
40+
position: Vec2::new(touch_input.location.x as f32, touch_input.location.y as f32),
41+
id: touch_input.id,
42+
}
43+
}
44+
3045
pub fn convert_virtual_key_code(virtual_key_code: winit::event::VirtualKeyCode) -> KeyCode {
3146
match virtual_key_code {
3247
winit::event::VirtualKeyCode::Key1 => KeyCode::Key1,

crates/bevy_winit/src/lib.rs

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ mod winit_windows;
44
use bevy_input::{
55
keyboard::KeyboardInput,
66
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
7+
touch::TouchInput,
78
};
89
pub use winit_config::*;
910
pub use winit_windows::*;
@@ -258,6 +259,11 @@ pub fn winit_runner(mut app: App) {
258259
});
259260
}
260261
},
262+
WindowEvent::Touch(touch) => {
263+
let mut touch_input_events =
264+
app.resources.get_mut::<Events<TouchInput>>().unwrap();
265+
touch_input_events.send(converters::convert_touch_input(touch));
266+
}
261267
_ => {}
262268
},
263269
event::Event::DeviceEvent { ref event, .. } => {

examples/input/touch_input.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
use bevy::{input::touch::*, prelude::*};
2+
3+
fn main() {
4+
App::build()
5+
.add_default_plugins()
6+
.init_resource::<TouchHandlerState>()
7+
.add_system(touch_system.system())
8+
.run();
9+
}
10+
11+
#[derive(Default)]
12+
struct TouchHandlerState {
13+
touch_event_reader: EventReader<TouchInput>,
14+
}
15+
16+
fn touch_system(
17+
mut state: ResMut<TouchHandlerState>,
18+
touch_events: Res<Events<TouchInput>>,
19+
touch_input_state: Res<TouchInputState>,
20+
) {
21+
for event in state.touch_event_reader.iter(&touch_events) {
22+
if touch_input_state.just_pressed.contains(&event.id) {
23+
println!(
24+
"just pressed touch with id: {:?}, at: {:?}",
25+
event.id, event.position
26+
);
27+
}
28+
29+
if touch_input_state.just_released.contains(&event.id) {
30+
println!(
31+
"just released touch with id: {:?}, at: {:?}",
32+
event.id, event.position
33+
);
34+
}
35+
36+
if touch_input_state.just_cancelled.contains(&event.id) {
37+
println!("cancelled touch with id: {:?}", event.id);
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)