Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mouse input accumulation #14044

Merged
merged 9 commits into from
Jul 1, 2024
18 changes: 16 additions & 2 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,11 @@ use bevy_ecs::prelude::*;
use bevy_reflect::Reflect;
use gestures::*;
use keyboard::{keyboard_input_system, KeyCode, KeyboardFocusLost, KeyboardInput};
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
use mouse::{
accumulate_mouse_motion_system, accumulate_mouse_scroll_system, mouse_button_input_system,
AccumulatedMouseMotion, AccumulatedMouseScroll, MouseButton, MouseButtonInput, MouseMotion,
MouseWheel,
};
use touch::{touch_screen_input_system, TouchInput, Touches};

use gamepad::{
Expand Down Expand Up @@ -77,7 +81,15 @@ impl Plugin for InputPlugin {
.add_event::<MouseMotion>()
.add_event::<MouseWheel>()
.init_resource::<ButtonInput<MouseButton>>()
.add_systems(PreUpdate, mouse_button_input_system.in_set(InputSystem))
.add_systems(
PreUpdate,
(
mouse_button_input_system,
accumulate_mouse_motion_system,
accumulate_mouse_scroll_system,
)
.in_set(InputSystem),
)
.add_event::<PinchGesture>()
.add_event::<RotationGesture>()
.add_event::<DoubleTapGesture>()
Expand All @@ -94,6 +106,8 @@ impl Plugin for InputPlugin {
.init_resource::<ButtonInput<GamepadButton>>()
.init_resource::<Axis<GamepadAxis>>()
.init_resource::<Axis<GamepadButton>>()
.init_resource::<AccumulatedMouseMotion>()
.init_resource::<AccumulatedMouseScroll>()
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
.add_systems(
PreUpdate,
(
Expand Down
77 changes: 77 additions & 0 deletions crates/bevy_input/src/mouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::{ButtonInput, ButtonState};
use bevy_ecs::entity::Entity;
use bevy_ecs::system::Resource;
use bevy_ecs::{
change_detection::DetectChangesMut,
event::{Event, EventReader},
Expand Down Expand Up @@ -155,3 +156,79 @@ pub fn mouse_button_input_system(
}
}
}

/// Tracks how much the mouse has moved every frame
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
/// This resource is reset to zero every frame
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
///
/// This resource sums the total [`MouseMotion`] events received this frame.
#[derive(Resource, Debug, Clone, Copy, PartialEq, Reflect, Default)]
#[reflect(Debug, PartialEq)]
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct AccumulatedMouseMotion {
/// The change in mouse position.
pub delta: Vec2,
}

/// Tracks how much the mouse has scrolled every frame
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
/// This resource is reset to zero every frame
Aztro-dev marked this conversation as resolved.
Show resolved Hide resolved
///
/// This resource sums the total [`MouseWheel`] events received this frame.
#[derive(Resource, Debug, Clone, Copy, PartialEq, Reflect)]
#[reflect(Debug, PartialEq)]
#[cfg_attr(
feature = "serialize",
derive(serde::Serialize, serde::Deserialize),
reflect(Serialize, Deserialize)
)]
pub struct AccumulatedMouseScroll {
/// The mouse scroll unit.
alice-i-cecile marked this conversation as resolved.
Show resolved Hide resolved
/// If this value changes while scrolling, then the
/// result of the accumulation could be incorrect
pub unit: MouseScrollUnit,
/// The change in scroll position.
pub delta: Vec2,
}

impl Default for AccumulatedMouseScroll {
fn default() -> Self {
Self {
unit: MouseScrollUnit::Line,
delta: Vec2::ZERO,
}
}
}

/// Updates the [`AccumulatedMouseMotion`] resource using the [`MouseMotion`] event.
/// The value of [`AccumulatedMouseMotion`] is reset to zero every frame
pub fn accumulate_mouse_motion_system(
mut mouse_motion_event: EventReader<MouseMotion>,
mut accumulated_mouse_motion: ResMut<AccumulatedMouseMotion>,
) {
let mut delta = Vec2::ZERO;
for event in mouse_motion_event.read() {
delta += event.delta;
}
accumulated_mouse_motion.delta = delta;
}

/// Updates the [`AccumulatedMouseScroll`] resource using the [`MouseWheel`] event.
/// The value of [`AccumulatedMouseScroll`] is reset to zero every frame
pub fn accumulate_mouse_scroll_system(
mut mouse_scroll_event: EventReader<MouseWheel>,
mut accumulated_mouse_scroll: ResMut<AccumulatedMouseScroll>,
) {
let mut delta = Vec2::ZERO;
let mut unit = MouseScrollUnit::Line;
for event in mouse_scroll_event.read() {
if event.unit != unit {
unit = event.unit;
}
delta += Vec2::new(event.x, event.y);
}
accumulated_mouse_scroll.delta = delta;
accumulated_mouse_scroll.unit = unit;
}
22 changes: 20 additions & 2 deletions examples/input/mouse_input.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
//! Prints mouse button events.

use bevy::prelude::*;
use bevy::{
input::mouse::{AccumulatedMouseMotion, AccumulatedMouseScroll},
prelude::*,
};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_systems(Update, mouse_click_system)
.add_systems(Update, (mouse_click_system, mouse_move_system))
.run();
}

Expand All @@ -23,3 +26,18 @@ fn mouse_click_system(mouse_button_input: Res<ButtonInput<MouseButton>>) {
info!("left mouse just released");
}
}

// This system prints messages when you finish dragging or scrolling with your mouse
fn mouse_move_system(
accumulated_mouse_motion: Res<AccumulatedMouseMotion>,
accumulated_mouse_scroll: Res<AccumulatedMouseScroll>,
) {
if accumulated_mouse_motion.delta != Vec2::ZERO {
let delta = accumulated_mouse_motion.delta;
info!("mouse moved ({}, {})", delta.x, delta.y);
}
if accumulated_mouse_scroll.delta != Vec2::ZERO {
let delta = accumulated_mouse_scroll.delta;
info!("mouse scrolled ({}, {})", delta.x, delta.y);
}
}