Skip to content

Commit 6dcff2b

Browse files
Aztro-devalice-i-cecileMrGVSV
authored
Mouse input accumulation (#14044)
# Objective - Add the `AccumulatedMouseMotion` and `AccumulatedMouseScroll` resources to make it simpler to track mouse motion/scroll changes - Closes #13915 ## Solution - Created two resources, `AccumulatedMouseMotion` and `AccumulatedMouseScroll`, and a method that tracks the `MouseMotion` and `MouseWheel` events and accumulates their deltas every frame. - Also modified the mouse input example to show how to use the resources. ## Testing - Tested the changes by modifying an existing example to use the newly added resources, and moving/scrolling my trackpad around a ton. --------- Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com> Co-authored-by: Gino Valente <49806985+MrGVSV@users.noreply.github.com>
1 parent f607be8 commit 6dcff2b

File tree

3 files changed

+120
-6
lines changed

3 files changed

+120
-6
lines changed

crates/bevy_input/src/lib.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,11 @@ use bevy_ecs::prelude::*;
4343
use bevy_reflect::Reflect;
4444
use gestures::*;
4545
use keyboard::{keyboard_input_system, KeyCode, KeyboardFocusLost, KeyboardInput};
46-
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
46+
use mouse::{
47+
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
48+
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
49+
MouseWheel,
50+
};
4751
use touch::{touch_screen_input_system, TouchInput, Touches};
4852

4953
use gamepad::{
@@ -77,7 +81,15 @@ impl Plugin for InputPlugin {
7781
.add_event::<MouseMotion>()
7882
.add_event::<MouseWheel>()
7983
.init_resource::<ButtonInput<MouseButton>>()
80-
.add_systems(PreUpdate, mouse_button_input_system.in_set(InputSystem))
84+
.add_systems(
85+
PreUpdate,
86+
(
87+
mouse_button_input_system,
88+
accumulate_mouse_motion_system,
89+
accumulate_mouse_scroll_system,
90+
)
91+
.in_set(InputSystem),
92+
)
8193
.add_event::<PinchGesture>()
8294
.add_event::<RotationGesture>()
8395
.add_event::<DoubleTapGesture>()
@@ -94,6 +106,8 @@ impl Plugin for InputPlugin {
94106
.init_resource::<ButtonInput<GamepadButton>>()
95107
.init_resource::<Axis<GamepadAxis>>()
96108
.init_resource::<Axis<GamepadButton>>()
109+
.init_resource::<AccumulatedMouseMotion>()
110+
.init_resource::<AccumulatedMouseScroll>()
97111
.add_systems(
98112
PreUpdate,
99113
(
@@ -124,7 +138,9 @@ impl Plugin for InputPlugin {
124138
.register_type::<TouchInput>()
125139
.register_type::<GamepadEvent>()
126140
.register_type::<GamepadButtonInput>()
127-
.register_type::<GamepadSettings>();
141+
.register_type::<GamepadSettings>()
142+
.register_type::<AccumulatedMouseMotion>()
143+
.register_type::<AccumulatedMouseScroll>();
128144
}
129145
}
130146

crates/bevy_input/src/mouse.rs

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,15 @@
22
33
use crate::{ButtonInput, ButtonState};
44
use bevy_ecs::entity::Entity;
5+
use bevy_ecs::reflect::ReflectResource;
6+
use bevy_ecs::system::Resource;
57
use bevy_ecs::{
68
change_detection::DetectChangesMut,
79
event::{Event, EventReader},
810
system::ResMut,
911
};
1012
use bevy_math::Vec2;
11-
use bevy_reflect::Reflect;
13+
use bevy_reflect::{std_traits::ReflectDefault, Reflect};
1214

1315
#[cfg(feature = "serialize")]
1416
use bevy_reflect::{ReflectDeserialize, ReflectSerialize};
@@ -155,3 +157,81 @@ pub fn mouse_button_input_system(
155157
}
156158
}
157159
}
160+
161+
/// Tracks how much the mouse has moved every frame.
162+
///
163+
/// This resource is reset to zero every frame.
164+
///
165+
/// This resource sums the total [`MouseMotion`] events received this frame.
166+
#[derive(Resource, Debug, Clone, Copy, PartialEq, Reflect, Default)]
167+
#[reflect(Debug, Default, Resource, PartialEq)]
168+
#[cfg_attr(
169+
feature = "serialize",
170+
derive(serde::Serialize, serde::Deserialize),
171+
reflect(Serialize, Deserialize)
172+
)]
173+
pub struct AccumulatedMouseMotion {
174+
/// The change in mouse position.
175+
pub delta: Vec2,
176+
}
177+
178+
/// Tracks how much the mouse has scrolled every frame.
179+
///
180+
/// This resource is reset to zero every frame.
181+
///
182+
/// This resource sums the total [`MouseWheel`] events received this frame.
183+
#[derive(Resource, Debug, Clone, Copy, PartialEq, Reflect)]
184+
#[reflect(Debug, Default, Resource, PartialEq)]
185+
#[cfg_attr(
186+
feature = "serialize",
187+
derive(serde::Serialize, serde::Deserialize),
188+
reflect(Serialize, Deserialize)
189+
)]
190+
pub struct AccumulatedMouseScroll {
191+
/// The mouse scroll unit.
192+
/// If this value changes while scrolling, then the
193+
/// result of the accumulation could be incorrect
194+
pub unit: MouseScrollUnit,
195+
/// The change in scroll position.
196+
pub delta: Vec2,
197+
}
198+
199+
impl Default for AccumulatedMouseScroll {
200+
fn default() -> Self {
201+
Self {
202+
unit: MouseScrollUnit::Line,
203+
delta: Vec2::ZERO,
204+
}
205+
}
206+
}
207+
208+
/// Updates the [`AccumulatedMouseMotion`] resource using the [`MouseMotion`] event.
209+
/// The value of [`AccumulatedMouseMotion`] is reset to zero every frame
210+
pub fn accumulate_mouse_motion_system(
211+
mut mouse_motion_event: EventReader<MouseMotion>,
212+
mut accumulated_mouse_motion: ResMut<AccumulatedMouseMotion>,
213+
) {
214+
let mut delta = Vec2::ZERO;
215+
for event in mouse_motion_event.read() {
216+
delta += event.delta;
217+
}
218+
accumulated_mouse_motion.delta = delta;
219+
}
220+
221+
/// Updates the [`AccumulatedMouseScroll`] resource using the [`MouseWheel`] event.
222+
/// The value of [`AccumulatedMouseScroll`] is reset to zero every frame
223+
pub fn accumulate_mouse_scroll_system(
224+
mut mouse_scroll_event: EventReader<MouseWheel>,
225+
mut accumulated_mouse_scroll: ResMut<AccumulatedMouseScroll>,
226+
) {
227+
let mut delta = Vec2::ZERO;
228+
let mut unit = MouseScrollUnit::Line;
229+
for event in mouse_scroll_event.read() {
230+
if event.unit != unit {
231+
unit = event.unit;
232+
}
233+
delta += Vec2::new(event.x, event.y);
234+
}
235+
accumulated_mouse_scroll.delta = delta;
236+
accumulated_mouse_scroll.unit = unit;
237+
}

examples/input/mouse_input.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
//! Prints mouse button events.
22
3-
use bevy::prelude::*;
3+
use bevy::{
4+
input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll},
5+
prelude::*,
6+
};
47

58
fn main() {
69
App::new()
710
.add_plugins(DefaultPlugins)
8-
.add_systems(Update, mouse_click_system)
11+
.add_systems(Update, (mouse_click_system, mouse_move_system))
912
.run();
1013
}
1114

@@ -23,3 +26,18 @@ fn mouse_click_system(mouse_button_input: Res<ButtonInput<MouseButton>>) {
2326
info!("left mouse just released");
2427
}
2528
}
29+
30+
// This system prints messages when you finish dragging or scrolling with your mouse
31+
fn mouse_move_system(
32+
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
33+
accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
34+
) {
35+
if accumulated_mouse_motion.delta != Vec2::ZERO {
36+
let delta = accumulated_mouse_motion.delta;
37+
info!("mouse moved ({}, {})", delta.x, delta.y);
38+
}
39+
if accumulated_mouse_scroll.delta != Vec2::ZERO {
40+
let delta = accumulated_mouse_scroll.delta;
41+
info!("mouse scrolled ({}, {})", delta.x, delta.y);
42+
}
43+
}

0 commit comments

Comments
 (0)