From 697e803ae92e572862f57d1d4c3405ea09514eec Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Tue, 13 Dec 2022 18:00:16 -0500 Subject: [PATCH 01/14] Refactor gilrs_event_system --- crates/bevy_gilrs/src/gilrs_system.rs | 35 +++++++++++++-------------- 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index d0bb67c5c28c6..2676fdde0c0ae 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -25,42 +25,41 @@ pub fn gilrs_event_system(mut gilrs: NonSendMut, mut events: EventWriter< { gilrs.update(&gilrs_event); - match gilrs_event.event { + let maybe_gamepad_event = match gilrs_event.event { EventType::Connected => { let pad = gilrs.gamepad(gilrs_event.id); let info = GamepadInfo { name: pad.name().into(), }; - events.send(GamepadEventRaw::new( - convert_gamepad_id(gilrs_event.id), - GamepadEventType::Connected(info), - )); + Some(GamepadEventType::Connected(info)) } EventType::Disconnected => { - events.send(GamepadEventRaw::new( - convert_gamepad_id(gilrs_event.id), - GamepadEventType::Disconnected, - )); + Some(GamepadEventRaw::new(gampad, GamepadEventType::Disconnected)); } EventType::ButtonChanged(gilrs_button, value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - events.send(GamepadEventRaw::new( - convert_gamepad_id(gilrs_event.id), - GamepadEventType::ButtonChanged(button_type, value), - )); + Some(GamepadEventType::ButtonChanged(button_type, value)) + } else { + None } } EventType::AxisChanged(gilrs_axis, value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - events.send(GamepadEventRaw::new( - convert_gamepad_id(gilrs_event.id), - GamepadEventType::AxisChanged(axis_type, value), - )); + Some(GamepadEventType::AxisChanged(axis_type, value)) + } else { + None } } - _ => (), + _ => None, }; + + if let Some(gamepad_event) = maybe_gamepad_event { + events.send(GamepadEventRaw { + gamepad: convert_gamepad_id(gilrs_event.id), + event_type: gamepad_event, + }); + } } gilrs.inc(); } From 2c717291e0179de39054934c130f267b8c10ca8f Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Tue, 13 Dec 2022 19:04:58 -0500 Subject: [PATCH 02/14] Rework gamepad event system --- crates/bevy_gilrs/src/gilrs_system.rs | 43 ++-- crates/bevy_input/src/gamepad.rs | 290 +++++++++++++++++++------- crates/bevy_input/src/lib.rs | 17 +- 3 files changed, 248 insertions(+), 102 deletions(-) diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 2676fdde0c0ae..eb35c1add8086 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -2,7 +2,10 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; use bevy_ecs::event::EventWriter; use bevy_ecs::system::{NonSend, NonSendMut}; use bevy_input::gamepad::GamepadInfo; -use bevy_input::{gamepad::GamepadEventRaw, prelude::*}; +use bevy_input::{ + gamepad::{GamepadConnectionEvent, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent}, + prelude::*, +}; use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; pub fn gilrs_event_startup_system(gilrs: NonSend, mut events: EventWriter) { @@ -25,41 +28,43 @@ pub fn gilrs_event_system(mut gilrs: NonSendMut, mut events: EventWriter< { gilrs.update(&gilrs_event); - let maybe_gamepad_event = match gilrs_event.event { + let gamepad = convert_gamepad_id(gilrs_event.id); + match gilrs_event.event { EventType::Connected => { let pad = gilrs.gamepad(gilrs_event.id); let info = GamepadInfo { name: pad.name().into(), }; - Some(GamepadEventType::Connected(info)) - } - EventType::Disconnected => { - Some(GamepadEventRaw::new(gampad, GamepadEventType::Disconnected)); + events.send(GamepadConnnectionEvent { + gamepad, + connection: GamepadConnection::Connected(info), + }) } + EventType::Disconnected => events.send(GamepadConnnectionEvent { + gamepad, + connection: GamepadConnection::Disconnected, + }), EventType::ButtonChanged(gilrs_button, value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - Some(GamepadEventType::ButtonChanged(button_type, value)) - } else { - None + events.send(RawGamepadButtonChangedEvent { + gamepad, + button: GamepadButton::new(gamepad, button_type), + unfiltered_value: value, + }) } } EventType::AxisChanged(gilrs_axis, value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - Some(GamepadEventType::AxisChanged(axis_type, value)) - } else { - None + events.send(RawGamepadAxisChangedEvent { + gamepad, + axis: GamepadAxis::new(gamepad, axis_type), + unfiltered_value: value, + }) } } _ => None, }; - - if let Some(gamepad_event) = maybe_gamepad_event { - events.send(GamepadEventRaw { - gamepad: convert_gamepad_id(gilrs_event.id), - event_type: gamepad_event, - }); - } } gilrs.inc(); } diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index c4f1ea22da099..ee538fff0071c 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1120,6 +1120,31 @@ impl ButtonAxisSettings { } } +/// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. +/// +/// ## Note +/// +/// Whenever a [`Gamepad`] connects or disconnects, an information gets printed to the console using the [`info!`] macro. +// pub fn gamepad_connection_system( +// mut gamepads: ResMut, +// mut gamepad_event: EventReader, +// ) { +// for event in gamepad_event.iter() { +// match &event.event_type { +// GamepadEventType::Connected(info) => { +// gamepads.register(event.gamepad, info.clone()); +// info!("{:?} Connected", event.gamepad); +// } + +// GamepadEventType::Disconnected => { +// gamepads.deregister(event.gamepad); +// info!("{:?} Disconnected", event.gamepad); +// } +// _ => (), +// } +// } +// } + /// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. /// /// ## Note @@ -1127,35 +1152,102 @@ impl ButtonAxisSettings { /// Whenever a [`Gamepad`] connects or disconnects, an information gets printed to the console using the [`info!`] macro. pub fn gamepad_connection_system( mut gamepads: ResMut, - mut gamepad_event: EventReader, + mut connection_events: EventReader, + mut axis: ResMut>, + mut button_axis: ResMut>, + mut button_input: ResMut>, ) { - for event in gamepad_event.iter() { - match &event.event_type { - GamepadEventType::Connected(info) => { - gamepads.register(event.gamepad, info.clone()); - info!("{:?} Connected", event.gamepad); + button_input.bypass_change_detection().clear(); + for connection_event in connection_events.iter() { + let gamepad = connection_event.gamepad; + + if let Gamepad::Connection(info) = connection_event.connection { + gamepads.register(gamepad, info.clone()); + info!("{:?} Connected", gamepad); + + for button_type in &ALL_BUTTON_TYPES { + let gamepad_button = GamepadButton::new(event.gamepad, *button_type); + button_input.reset(gamepad_button); + button_axis.set(gamepad_button, 0.0); } + for axis_type in &ALL_AXIS_TYPES { + axis.set(GamepadAxis::new(event.gamepad, *axis_type), 0.0); + } + } else { + gamepads.deregister(gamepad); + info!("{:?} Disconnected", gamepad); - GamepadEventType::Disconnected => { - gamepads.deregister(event.gamepad); - info!("{:?} Disconnected", event.gamepad); + for button_type in &ALL_BUTTON_TYPES { + let gamepad_button = GamepadButton::new(gamepad, *button_type); + button_input.reset(gamepad_button); + button_axis.remove(gamepad_button); + } + for axis_type in &ALL_AXIS_TYPES { + axis.remove(GamepadAxis::new(gamepad, *axis_type)); } - _ => (), } } } -/// Modifies the gamepad resources and sends out gamepad events. -/// -/// The resources [`Input`], [`Axis`], and [`Axis`] are updated -/// and the [`GamepadEvent`]s are sent according to the received [`GamepadEventRaw`]s respecting the [`GamepadSettings`]. -/// -/// ## Differences -/// -/// The main difference between the events and the resources is that the latter allows you to check specific -/// buttons or axes, rather than reading the events one at a time. This is done through convenient functions -/// like [`Input::pressed`], [`Input::just_pressed`], [`Input::just_released`], and [`Axis::get`]. -pub fn gamepad_event_system( +enum GamepadConnection { + Connected(GamepadInfo), + Disconnected, +} + +pub struct GamepadConnectionEvent { + pub gamepad: Gamepad, + pub connection: GamepadConnection, +} + +pub struct RawGamepadAxisChangedEvent { + pub gamepad: Gamepad, + pub axis: GamepadAxis, + pub unfiltered_value: f32, +} + +pub struct GamepadAxisChangedEvent { + pub gamepad: Gamepad, + pub axis: GamepadAxis, + pub value: f32, +} + +pub struct RawGamepadButtonChangedEvent { + pub gamepad: Gamepad, + pub button: GamepadButton, + pub unfiltered_value: f32, +} + +pub struct GamepadButtonChangedEvent { + pub gamepad: Gamepad, + pub button: GamepadButton, + pub value: f32, +} + +pub fn gamepad_raw_axis_event_system( + mut button_input: ResMut>, + mut axis: ResMut>, + mut button_axis: ResMut>, + mut raw_axis_events: EventReader, + mut events: EventWriter, + settings: Res, +) { + button_input.bypass_change_detection().clear(); + for RawGamepadAxisEvent(gamepad, gamepad_axis) in raw_events.iter() { + if let Some(filtered_value) = settings + .get_axis_settings(gamepad_axis) + .filter(*value, axis.get(gamepad_axis)) + { + axis.set(gamepad_axis, filtered_value); + events.send(GamepadAxisChangedEvent { + gamepad, + axis: gamepad_axis, + value: filtered_value, + }); + } + } +} + +pub fn gamepad_raw_button_event_system( mut button_input: ResMut>, mut axis: ResMut>, mut button_axis: ResMut>, @@ -1164,69 +1256,109 @@ pub fn gamepad_event_system( settings: Res, ) { button_input.bypass_change_detection().clear(); - for event in raw_events.iter() { - match &event.event_type { - GamepadEventType::Connected(_) => { - events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); - for button_type in &ALL_BUTTON_TYPES { - let gamepad_button = GamepadButton::new(event.gamepad, *button_type); - button_input.reset(gamepad_button); - button_axis.set(gamepad_button, 0.0); - } - for axis_type in &ALL_AXIS_TYPES { - axis.set(GamepadAxis::new(event.gamepad, *axis_type), 0.0); - } - } - GamepadEventType::Disconnected => { - events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); - for button_type in &ALL_BUTTON_TYPES { - let gamepad_button = GamepadButton::new(event.gamepad, *button_type); - button_input.reset(gamepad_button); - button_axis.remove(gamepad_button); - } - for axis_type in &ALL_AXIS_TYPES { - axis.remove(GamepadAxis::new(event.gamepad, *axis_type)); - } - } - GamepadEventType::AxisChanged(axis_type, value) => { - let gamepad_axis = GamepadAxis::new(event.gamepad, *axis_type); - if let Some(filtered_value) = settings - .get_axis_settings(gamepad_axis) - .filter(*value, axis.get(gamepad_axis)) - { - axis.set(gamepad_axis, filtered_value); - events.send(GamepadEvent::new( - event.gamepad, - GamepadEventType::AxisChanged(*axis_type, filtered_value), - )); - } - } - GamepadEventType::ButtonChanged(button_type, value) => { - let gamepad_button = GamepadButton::new(event.gamepad, *button_type); - if let Some(filtered_value) = settings - .get_button_axis_settings(gamepad_button) - .filter(*value, button_axis.get(gamepad_button)) - { - button_axis.set(gamepad_button, filtered_value); - events.send(GamepadEvent::new( - event.gamepad, - GamepadEventType::ButtonChanged(*button_type, filtered_value), - )); - } + for RawGamepadButtonChangedEvent(gamepad, gamepad_button, value) in raw_button_events.iter() { + if let Some(filtered_value) = settings + .get_button_axis_settings(gamepad_button) + .filter(*value, button_axis.get(gamepad_button)) + { + button_axis.set(gamepad_button, filtered_value); + events.send(GamepadButtonChangedEvent { + gamepad, + button, + value: filtered_value, + }); + } - let button_property = settings.get_button_settings(gamepad_button); - if button_input.pressed(gamepad_button) { - if button_property.is_released(*value) { - button_input.release(gamepad_button); - } - } else if button_property.is_pressed(*value) { - button_input.press(gamepad_button); - } - } + let button_property = settings.get_button_settings(gamepad_button); + if button_property.is_released(*value) { + button_input.release(gamepad_button); + } else if button_property.is_pressed(*value) { + button_input.press(gamepad_button); } } } +/// Modifies the gamepad resources and sends out gamepad events. +/// +/// The resources [`Input`], [`Axis`], and [`Axis`] are updated +/// and the [`GamepadEvent`]s are sent according to the received [`GamepadEventRaw`]s respecting the [`GamepadSettings`]. +/// +/// ## Differences +/// +/// The main difference between the events and the resources is that the latter allows you to check specific +/// buttons or axes, rather than reading the events one at a time. This is done through convenient functions +/// like [`Input::pressed`], [`Input::just_pressed`], [`Input::just_released`], and [`Axis::get`]. +// pub fn gamepad_event_system( +// mut button_input: ResMut>, +// mut axis: ResMut>, +// mut button_axis: ResMut>, +// mut raw_events: EventReader, +// mut events: EventWriter, +// settings: Res, +// ) { +// button_input.bypass_change_detection().clear(); +// for event in raw_events.iter() { +// match &event.event_type { +// GamepadEventType::Connected(_) => { +// events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); +// for button_type in &ALL_BUTTON_TYPES { +// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); +// button_input.reset(gamepad_button); +// button_axis.set(gamepad_button, 0.0); +// } +// for axis_type in &ALL_AXIS_TYPES { +// axis.set(GamepadAxis::new(event.gamepad, *axis_type), 0.0); +// } +// } +// GamepadEventType::Disconnected => { +// events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); +// for button_type in &ALL_BUTTON_TYPES { +// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); +// button_input.reset(gamepad_button); +// button_axis.remove(gamepad_button); +// } +// for axis_type in &ALL_AXIS_TYPES { +// axis.remove(GamepadAxis::new(event.gamepad, *axis_type)); +// } +// } +// GamepadEventType::AxisChanged(axis_type, value) => { +// let gamepad_axis = GamepadAxis::new(event.gamepad, *axis_type); +// if let Some(filtered_value) = settings +// .get_axis_settings(gamepad_axis) +// .filter(*value, axis.get(gamepad_axis)) +// { +// axis.set(gamepad_axis, filtered_value); +// events.send(GamepadEvent::new( +// event.gamepad, +// GamepadEventType::AxisChanged(*axis_type, filtered_value), +// )); +// } +// } +// GamepadEventType::ButtonChanged(button_type, value) => { +// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); +// if let Some(filtered_value) = settings +// .get_button_axis_settings(gamepad_button) +// .filter(*value, button_axis.get(gamepad_button)) +// { +// button_axis.set(gamepad_button, filtered_value); +// events.send(GamepadEvent::new( +// event.gamepad, +// GamepadEventType::ButtonChanged(*button_type, filtered_value), +// )); +// } + +// let button_property = settings.get_button_settings(gamepad_button); +// if button_property.is_released(*value) { +// button_input.release(gamepad_button); +// } else if button_property.is_pressed(*value) { +// button_input.press(gamepad_button); +// } +// } +// _ => (), +// } +// } +// } + /// An array of every [`GamepadButtonType`] variant. const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [ GamepadButtonType::South, diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 23583667ae973..1725e78867167 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -33,9 +33,10 @@ use mouse::{ use touch::{touch_screen_input_system, ForceTouch, TouchInput, TouchPhase, Touches}; use gamepad::{ - gamepad_connection_system, gamepad_event_system, AxisSettings, ButtonAxisSettings, - ButtonSettings, Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, - GamepadEvent, GamepadEventRaw, GamepadEventType, GamepadSettings, Gamepads, + gamepad_connection_system, gamepad_event_system, gamepad_raw_button_event_handler, + AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, GamepadAxisType, + GamepadButton, GamepadButtonType, GamepadEvent, GamepadEventRaw, GamepadEventType, + GamepadSettings, Gamepads, }; #[cfg(feature = "serialize")] @@ -78,7 +79,11 @@ impl Plugin for InputPlugin { .init_resource::>() .add_system_to_stage( CoreStage::PreUpdate, - gamepad_event_system.label(InputSystem), + gamepad_raw_button_event_system.label(InputSystem), + ) + .add_system_to_stage( + CoreStage::PreUpdate, + gamepad_raw_axis_event_system.after(InputSystem), ) .add_system_to_stage( CoreStage::PreUpdate, @@ -145,4 +150,8 @@ impl ButtonState { pub fn is_pressed(&self) -> bool { matches!(self, ButtonState::Pressed) } + + pub fn is_released(&self) -> bool { + matches!(self, ButtonState::Released) + } } From d24e6fce31aa4a938f5819df75d6badc4df7a80c Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Tue, 13 Dec 2022 19:45:53 -0500 Subject: [PATCH 03/14] Fixed build errors --- crates/bevy_app/src/app.rs | 1 + crates/bevy_gilrs/src/gilrs_system.rs | 41 +++-- crates/bevy_input/src/gamepad.rs | 231 ++++++++++++++++---------- crates/bevy_input/src/input.rs | 12 ++ crates/bevy_input/src/keyboard.rs | 10 ++ crates/bevy_input/src/lib.rs | 26 +-- crates/bevy_input/src/mouse.rs | 10 ++ 7 files changed, 215 insertions(+), 116 deletions(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index d88a82059126c..5497230ed9f73 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -122,6 +122,7 @@ impl App { /// Creates a new [`App`] with some default structure to enable core engine features. /// This is the preferred constructor for most use cases. pub fn new() -> App { + println!("THIS IS A TEST VERSION"); App::default() } diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index eb35c1add8086..7e3d863a787c8 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -3,25 +3,36 @@ use bevy_ecs::event::EventWriter; use bevy_ecs::system::{NonSend, NonSendMut}; use bevy_input::gamepad::GamepadInfo; use bevy_input::{ - gamepad::{GamepadConnectionEvent, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent}, + gamepad::{ + GamepadConnection, GamepadConnectionEvent, RawGamepadAxisChangedEvent, + RawGamepadButtonChangedEvent, + }, prelude::*, }; use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; -pub fn gilrs_event_startup_system(gilrs: NonSend, mut events: EventWriter) { +pub fn gilrs_event_startup_system( + gilrs: NonSend, + mut connection_events: EventWriter, +) { for (id, gamepad) in gilrs.gamepads() { let info = GamepadInfo { name: gamepad.name().into(), }; - events.send(GamepadEventRaw::new( - convert_gamepad_id(id), - GamepadEventType::Connected(info), - )); + connection_events.send(GamepadConnectionEvent { + gamepad: convert_gamepad_id(id), + connection: GamepadConnection::Connected(info), + }); } } -pub fn gilrs_event_system(mut gilrs: NonSendMut, mut events: EventWriter) { +pub fn gilrs_event_system( + mut gilrs: NonSendMut, + mut axis_events: EventWriter, + mut button_events: EventWriter, + mut connection_events: EventWriter, +) { while let Some(gilrs_event) = gilrs .next_event() .filter_ev(&axis_dpad_to_button, &mut gilrs) @@ -36,34 +47,34 @@ pub fn gilrs_event_system(mut gilrs: NonSendMut, mut events: EventWriter< name: pad.name().into(), }; - events.send(GamepadConnnectionEvent { + connection_events.send(GamepadConnectionEvent { gamepad, connection: GamepadConnection::Connected(info), - }) + }); } - EventType::Disconnected => events.send(GamepadConnnectionEvent { + EventType::Disconnected => connection_events.send(GamepadConnectionEvent { gamepad, connection: GamepadConnection::Disconnected, }), EventType::ButtonChanged(gilrs_button, value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - events.send(RawGamepadButtonChangedEvent { + button_events.send(RawGamepadButtonChangedEvent { gamepad, button: GamepadButton::new(gamepad, button_type), unfiltered_value: value, - }) + }); } } EventType::AxisChanged(gilrs_axis, value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - events.send(RawGamepadAxisChangedEvent { + axis_events.send(RawGamepadAxisChangedEvent { gamepad, axis: GamepadAxis::new(gamepad, axis_type), unfiltered_value: value, - }) + }); } } - _ => None, + _ => (), }; } gilrs.inc(); diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index ee538fff0071c..47803a7ec0613 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -146,24 +146,24 @@ impl Gamepads { } /// The data contained in a [`GamepadEvent`] or [`GamepadEventRaw`]. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -#[reflect(Debug, PartialEq)] -#[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), - reflect(Serialize, Deserialize) -)] -pub enum GamepadEventType { - /// A [`Gamepad`] has been connected. - Connected(GamepadInfo), - /// A [`Gamepad`] has been disconnected. - Disconnected, - - /// The value of a [`Gamepad`] button has changed. - ButtonChanged(GamepadButtonType, f32), - /// The value of a [`Gamepad`] axis has changed. - AxisChanged(GamepadAxisType, f32), -} +// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +// #[reflect(Debug, PartialEq)] +// #[cfg_attr( +// feature = "serialize", +// derive(serde::Serialize, serde::Deserialize), +// reflect(Serialize, Deserialize) +// )] +// pub enum GamepadEventType { +// /// A [`Gamepad`] has been connected. +// Connected(GamepadInfo), +// /// A [`Gamepad`] has been disconnected. +// Disconnected, + +// /// The value of a [`Gamepad`] button has changed. +// ButtonChanged(GamepadButtonType, f32), +// /// The value of a [`Gamepad`] axis has changed. +// AxisChanged(GamepadAxisType, f32), +// } /// An event of a [`Gamepad`]. /// @@ -184,29 +184,29 @@ pub enum GamepadEventType { /// [`Axis`], and [`Axis`] resources won't be updated correctly. /// /// An example for gamepad input mocking can be seen in the documentation of the [`GamepadEventRaw`]. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -#[reflect(Debug, PartialEq)] -#[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), - reflect(Serialize, Deserialize) -)] -pub struct GamepadEvent { - /// The gamepad this event corresponds to. - pub gamepad: Gamepad, - /// The type of the event. - pub event_type: GamepadEventType, -} +// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +// #[reflect(Debug, PartialEq)] +// #[cfg_attr( +// feature = "serialize", +// derive(serde::Serialize, serde::Deserialize), +// reflect(Serialize, Deserialize) +// )] +// pub struct GamepadEvent { +// /// The gamepad this event corresponds to. +// pub gamepad: Gamepad, +// /// The type of the event. +// pub event_type: GamepadEventType, +// } -impl GamepadEvent { - /// Creates a new [`GamepadEvent`]. - pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { - Self { - gamepad, - event_type, - } - } -} +// impl GamepadEvent { +// /// Creates a new [`GamepadEvent`]. +// pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { +// Self { +// gamepad, +// event_type, +// } +// } +// } /// A raw event of a [`Gamepad`]. /// @@ -293,29 +293,29 @@ impl GamepadEvent { /// # /// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press); /// ``` -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -#[reflect(Debug, PartialEq)] -#[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), - reflect(Serialize, Deserialize) -)] -pub struct GamepadEventRaw { - /// The gamepad this event corresponds to. - pub gamepad: Gamepad, - /// The type of the event. - pub event_type: GamepadEventType, -} +// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +// #[reflect(Debug, PartialEq)] +// #[cfg_attr( +// feature = "serialize", +// derive(serde::Serialize, serde::Deserialize), +// reflect(Serialize, Deserialize) +// )] +// pub struct GamepadEventRaw { +// /// The gamepad this event corresponds to. +// pub gamepad: Gamepad, +// /// The type of the event. +// pub event_type: GamepadEventType, +// } -impl GamepadEventRaw { - /// Creates a new [`GamepadEventRaw`]. - pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { - Self { - gamepad, - event_type, - } - } -} +// impl GamepadEventRaw { +// /// Creates a new [`GamepadEventRaw`]. +// pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { +// Self { +// gamepad, +// event_type, +// } +// } +// } /// A type of a [`GamepadButton`]. /// @@ -1161,17 +1161,17 @@ pub fn gamepad_connection_system( for connection_event in connection_events.iter() { let gamepad = connection_event.gamepad; - if let Gamepad::Connection(info) = connection_event.connection { + if let GamepadConnection::Connected(info) = &connection_event.connection { gamepads.register(gamepad, info.clone()); info!("{:?} Connected", gamepad); for button_type in &ALL_BUTTON_TYPES { - let gamepad_button = GamepadButton::new(event.gamepad, *button_type); + let gamepad_button = GamepadButton::new(gamepad, *button_type); button_input.reset(gamepad_button); button_axis.set(gamepad_button, 0.0); } for axis_type in &ALL_AXIS_TYPES { - axis.set(GamepadAxis::new(event.gamepad, *axis_type), 0.0); + axis.set(GamepadAxis::new(gamepad, *axis_type), 0.0); } } else { gamepads.deregister(gamepad); @@ -1188,35 +1188,76 @@ pub fn gamepad_connection_system( } } } - -enum GamepadConnection { +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub enum GamepadConnection { Connected(GamepadInfo), Disconnected, } +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct GamepadConnectionEvent { pub gamepad: Gamepad, pub connection: GamepadConnection, } +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct RawGamepadAxisChangedEvent { pub gamepad: Gamepad, pub axis: GamepadAxis, pub unfiltered_value: f32, } +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct GamepadAxisChangedEvent { pub gamepad: Gamepad, pub axis: GamepadAxis, pub value: f32, } +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct RawGamepadButtonChangedEvent { pub gamepad: Gamepad, pub button: GamepadButton, pub unfiltered_value: f32, } +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] pub struct GamepadButtonChangedEvent { pub gamepad: Gamepad, pub button: GamepadButton, @@ -1225,22 +1266,27 @@ pub struct GamepadButtonChangedEvent { pub fn gamepad_raw_axis_event_system( mut button_input: ResMut>, - mut axis: ResMut>, + mut gamepad_axis: ResMut>, mut button_axis: ResMut>, mut raw_axis_events: EventReader, - mut events: EventWriter, + mut axis_events: EventWriter, settings: Res, ) { button_input.bypass_change_detection().clear(); - for RawGamepadAxisEvent(gamepad, gamepad_axis) in raw_events.iter() { + for RawGamepadAxisChangedEvent { + gamepad, + axis, + unfiltered_value, + } in raw_axis_events.iter() + { if let Some(filtered_value) = settings - .get_axis_settings(gamepad_axis) - .filter(*value, axis.get(gamepad_axis)) + .get_axis_settings(*axis) + .filter(*unfiltered_value, gamepad_axis.get(*axis)) { - axis.set(gamepad_axis, filtered_value); - events.send(GamepadAxisChangedEvent { - gamepad, - axis: gamepad_axis, + gamepad_axis.set(*axis, filtered_value); + axis_events.send(GamepadAxisChangedEvent { + gamepad: *gamepad, + axis: *axis, value: filtered_value, }); } @@ -1248,32 +1294,37 @@ pub fn gamepad_raw_axis_event_system( } pub fn gamepad_raw_button_event_system( + mut raw_button_events: EventReader, + mut button_events: EventWriter, mut button_input: ResMut>, mut axis: ResMut>, mut button_axis: ResMut>, - mut raw_events: EventReader, - mut events: EventWriter, settings: Res, ) { button_input.bypass_change_detection().clear(); - for RawGamepadButtonChangedEvent(gamepad, gamepad_button, value) in raw_button_events.iter() { + for RawGamepadButtonChangedEvent { + gamepad, + button, + unfiltered_value, + } in raw_button_events.iter() + { if let Some(filtered_value) = settings - .get_button_axis_settings(gamepad_button) - .filter(*value, button_axis.get(gamepad_button)) + .get_button_axis_settings(*button) + .filter(*unfiltered_value, button_axis.get(*button)) { - button_axis.set(gamepad_button, filtered_value); - events.send(GamepadButtonChangedEvent { - gamepad, - button, + button_axis.set(*button, filtered_value); + button_events.send(GamepadButtonChangedEvent { + gamepad: *gamepad, + button: *button, value: filtered_value, }); } - let button_property = settings.get_button_settings(gamepad_button); - if button_property.is_released(*value) { - button_input.release(gamepad_button); - } else if button_property.is_pressed(*value) { - button_input.press(gamepad_button); + let button_property = settings.get_button_settings(*button); + if button_property.is_released(*unfiltered_value) { + button_input.release(*button); + } else if button_property.is_pressed(*unfiltered_value) { + button_input.press(*button); } } } diff --git a/crates/bevy_input/src/input.rs b/crates/bevy_input/src/input.rs index 3d1a1ecf5a9ad..25c0dd9b7f61c 100644 --- a/crates/bevy_input/src/input.rs +++ b/crates/bevy_input/src/input.rs @@ -7,6 +7,17 @@ use std::hash::Hash; #[allow(unused_imports)] use bevy_ecs::schedule::State; +// type PressableInput = Copy + Eq + Hash + Send + Sync + 'static; + +pub trait PressableInputEvent { + fn just_pressed(&self) -> bool; + fn just_released(&self) -> bool; +} + +// pub trait PressableInputValue { +// fn get_value(&self) -> T; +// } + /// A "press-able" input of type `T`. /// /// ## Usage @@ -44,6 +55,7 @@ use bevy_ecs::schedule::State; #[derive(Debug, Clone, Resource, Reflect)] #[reflect(Default)] pub struct Input { + // : PressableInput> { /// A collection of every button that is currently being pressed. pressed: HashSet, /// A collection of every button that has just been pressed. diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 021646015be7c..15ce329d5a395 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -30,6 +30,16 @@ pub struct KeyboardInput { pub state: ButtonState, } +// impl PressableInputEvent for KeyboardInput { +// fn just_pressed(&self) -> bool { +// self.state.is_pressed() +// } + +// fn just_released(&self) -> bool { +// self.state.is_released() +// } +// } + /// Updates the [`Input`] resource with the latest [`KeyboardInput`] events. /// /// ## Differences diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 1725e78867167..2b4ae5060af2a 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -12,8 +12,7 @@ pub mod prelude { #[doc(hidden)] pub use crate::{ gamepad::{ - Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent, - GamepadEventType, Gamepads, + Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, Gamepads, }, keyboard::{KeyCode, ScanCode}, mouse::MouseButton, @@ -33,10 +32,11 @@ use mouse::{ use touch::{touch_screen_input_system, ForceTouch, TouchInput, TouchPhase, Touches}; use gamepad::{ - gamepad_connection_system, gamepad_event_system, gamepad_raw_button_event_handler, - AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, GamepadAxisType, - GamepadButton, GamepadButtonType, GamepadEvent, GamepadEventRaw, GamepadEventType, - GamepadSettings, Gamepads, + gamepad_connection_system, gamepad_raw_axis_event_system, gamepad_raw_button_event_system, + AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, + GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonChangedEvent, + GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, + RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, }; #[cfg(feature = "serialize")] @@ -70,8 +70,11 @@ impl Plugin for InputPlugin { mouse_button_input_system.label(InputSystem), ) // gamepad - .add_event::() - .add_event::() + .add_event::() + .add_event::() + .add_event::() + .add_event::() + .add_event::() .init_resource::() .init_resource::() .init_resource::>() @@ -119,9 +122,10 @@ impl Plugin for InputPlugin { // Register gamepad types app.register_type::() - .register_type::() - .register_type::() - .register_type::() + .register_type::() + // .register_type::() + // .register_type::() + // .register_type::() .register_type::() .register_type::() .register_type::() diff --git a/crates/bevy_input/src/mouse.rs b/crates/bevy_input/src/mouse.rs index bf86ed55b22ea..022ba82cd963e 100644 --- a/crates/bevy_input/src/mouse.rs +++ b/crates/bevy_input/src/mouse.rs @@ -28,6 +28,16 @@ pub struct MouseButtonInput { pub state: ButtonState, } +// impl PressableInputEvent for MouseButtonInput { +// fn just_pressed(&self) -> bool { +// self.state.is_pressed() +// } + +// fn just_released(&self) -> bool { +// self.state.is_released() +// } +// } + /// A button on a mouse device. /// /// ## Usage From fa399372087f0eff0944c96a9022071cc58c3d9a Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Tue, 13 Dec 2022 19:50:47 -0500 Subject: [PATCH 04/14] Fix warnings --- crates/bevy_input/src/gamepad.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 47803a7ec0613..77602707313d2 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1267,7 +1267,6 @@ pub struct GamepadButtonChangedEvent { pub fn gamepad_raw_axis_event_system( mut button_input: ResMut>, mut gamepad_axis: ResMut>, - mut button_axis: ResMut>, mut raw_axis_events: EventReader, mut axis_events: EventWriter, settings: Res, @@ -1297,7 +1296,6 @@ pub fn gamepad_raw_button_event_system( mut raw_button_events: EventReader, mut button_events: EventWriter, mut button_input: ResMut>, - mut axis: ResMut>, mut button_axis: ResMut>, settings: Res, ) { From d7f87c93b25810f2dbb8b20769d23c2a36f571a5 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Thu, 15 Dec 2022 20:06:55 -0500 Subject: [PATCH 05/14] Constructors for events. Comments. and methods. gilrs_event_system updates. --- crates/bevy_gilrs/src/gilrs_system.rs | 23 +- crates/bevy_input/src/gamepad.rs | 449 +++++++++++--------------- crates/bevy_input/src/input.rs | 12 - crates/bevy_input/src/keyboard.rs | 10 - crates/bevy_input/src/lib.rs | 17 +- crates/bevy_input/src/mouse.rs | 10 - 6 files changed, 198 insertions(+), 323 deletions(-) diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index 7e3d863a787c8..cbe95bfab8a45 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -2,12 +2,9 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; use bevy_ecs::event::EventWriter; use bevy_ecs::system::{NonSend, NonSendMut}; use bevy_input::gamepad::GamepadInfo; -use bevy_input::{ - gamepad::{ - GamepadConnection, GamepadConnectionEvent, RawGamepadAxisChangedEvent, - RawGamepadButtonChangedEvent, - }, - prelude::*, +use bevy_input::gamepad::{ + GamepadConnection, GamepadConnectionEvent, RawGamepadAxisChangedEvent, + RawGamepadButtonChangedEvent, }; use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; @@ -58,20 +55,16 @@ pub fn gilrs_event_system( }), EventType::ButtonChanged(gilrs_button, value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - button_events.send(RawGamepadButtonChangedEvent { + button_events.send(RawGamepadButtonChangedEvent::new( gamepad, - button: GamepadButton::new(gamepad, button_type), - unfiltered_value: value, - }); + button_type, + value, + )); } } EventType::AxisChanged(gilrs_axis, value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - axis_events.send(RawGamepadAxisChangedEvent { - gamepad, - axis: GamepadAxis::new(gamepad, axis_type), - unfiltered_value: value, - }); + axis_events.send(RawGamepadAxisChangedEvent::new(gamepad, axis_type, value)); } } _ => (), diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 77602707313d2..329f1f4f529da 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,4 +1,4 @@ -use crate::{Axis, Input}; +use crate::{Axis, ButtonState, Input}; use bevy_ecs::event::{EventReader, EventWriter}; use bevy_ecs::{ change_detection::DetectChanges, @@ -145,26 +145,6 @@ impl Gamepads { } } -/// The data contained in a [`GamepadEvent`] or [`GamepadEventRaw`]. -// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -// #[reflect(Debug, PartialEq)] -// #[cfg_attr( -// feature = "serialize", -// derive(serde::Serialize, serde::Deserialize), -// reflect(Serialize, Deserialize) -// )] -// pub enum GamepadEventType { -// /// A [`Gamepad`] has been connected. -// Connected(GamepadInfo), -// /// A [`Gamepad`] has been disconnected. -// Disconnected, - -// /// The value of a [`Gamepad`] button has changed. -// ButtonChanged(GamepadButtonType, f32), -// /// The value of a [`Gamepad`] axis has changed. -// AxisChanged(GamepadAxisType, f32), -// } - /// An event of a [`Gamepad`]. /// /// This event is the translated version of the [`GamepadEventRaw`]. It is available to @@ -184,29 +164,6 @@ impl Gamepads { /// [`Axis`], and [`Axis`] resources won't be updated correctly. /// /// An example for gamepad input mocking can be seen in the documentation of the [`GamepadEventRaw`]. -// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -// #[reflect(Debug, PartialEq)] -// #[cfg_attr( -// feature = "serialize", -// derive(serde::Serialize, serde::Deserialize), -// reflect(Serialize, Deserialize) -// )] -// pub struct GamepadEvent { -// /// The gamepad this event corresponds to. -// pub gamepad: Gamepad, -// /// The type of the event. -// pub event_type: GamepadEventType, -// } - -// impl GamepadEvent { -// /// Creates a new [`GamepadEvent`]. -// pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { -// Self { -// gamepad, -// event_type, -// } -// } -// } /// A raw event of a [`Gamepad`]. /// @@ -229,7 +186,7 @@ impl Gamepads { /// ``` /// # use bevy_input::prelude::*; /// # use bevy_input::InputPlugin; -/// # use bevy_input::gamepad::{GamepadEventRaw, GamepadInfo}; +/// # use bevy_input::gamepad::{GamepadConnectionEvent, GamepadConnection, RawGamepadButtonChangedEvent, GamepadInfo}; /// # use bevy_app::prelude::*; /// # use bevy_ecs::prelude::*; /// #[derive(Resource)] @@ -262,13 +219,14 @@ impl Gamepads { /// // Send the gamepad connected event to mark our gamepad as connected. /// // This updates the `Gamepads` resource accordingly. /// let info = GamepadInfo { name: "Mock Gamepad".into() }; -/// app.world.send_event(GamepadEventRaw::new(gamepad, GamepadEventType::Connected(info))); +/// app.world.send_event(GamepadConnectionEvent::new(gamepad, GamepadConnection::Connected(info))); /// /// // Send the gamepad input event to mark the `South` gamepad button as pressed. /// // This updates the `Input` resource accordingly. -/// app.world.send_event(GamepadEventRaw::new( +/// app.world.send_event(RawGamepadButtonChangedEvent::new( /// gamepad, -/// GamepadEventType::ButtonChanged(button_type, 1.0) +/// button_type, +/// 1.0, /// )); /// /// // Advance the execution of the schedule by a single cycle. @@ -280,9 +238,10 @@ impl Gamepads { /// /// // Send the gamepad input event to mark the `South` gamepad button as released. /// // This updates the `Input` resource accordingly. -/// app.world.send_event(GamepadEventRaw::new( +/// app.world.send_event(RawGamepadButtonChangedEvent::new( /// gamepad, -/// GamepadEventType::ButtonChanged(button_type, 0.0) +/// button_type, +/// 0.0 /// )); /// /// // Advance the execution of the schedule by another cycle. @@ -293,29 +252,6 @@ impl Gamepads { /// # /// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press); /// ``` -// #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -// #[reflect(Debug, PartialEq)] -// #[cfg_attr( -// feature = "serialize", -// derive(serde::Serialize, serde::Deserialize), -// reflect(Serialize, Deserialize) -// )] -// pub struct GamepadEventRaw { -// /// The gamepad this event corresponds to. -// pub gamepad: Gamepad, -// /// The type of the event. -// pub event_type: GamepadEventType, -// } - -// impl GamepadEventRaw { -// /// Creates a new [`GamepadEventRaw`]. -// pub fn new(gamepad: Gamepad, event_type: GamepadEventType) -> Self { -// Self { -// gamepad, -// event_type, -// } -// } -// } /// A type of a [`GamepadButton`]. /// @@ -430,7 +366,7 @@ impl GamepadButton { /// ## Usage /// /// This is used to determine which axis has changed its value when receiving a -/// [`GamepadEventType::AxisChanged`]. It is also used in the [`GamepadAxis`] +/// [`RawGamepadAxisChangedEvent`]. It is also used in the [`GamepadAxis`] /// which in turn is used to create the [`Axis`] `bevy` resource. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] @@ -467,7 +403,7 @@ pub enum GamepadAxisType { /// /// ## Updating /// -/// The resource is updated inside of the [`gamepad_event_system`]. +/// The resource is updated inside of the gamepad event handling systems. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( @@ -510,7 +446,7 @@ impl GamepadAxis { /// /// ## Note /// -/// The [`GamepadSettings`] are used inside of the [`gamepad_event_system`], but are never written to +/// The [`GamepadSettings`] are used inside of the gamepad event handling systems, but are never written to /// inside of `bevy`. To modify these settings, mutate the corresponding resource. #[derive(Resource, Default, Debug, Reflect, FromReflect)] #[reflect(Debug, Default)] @@ -1032,25 +968,40 @@ impl AxisSettings { self.threshold } - fn filter(&self, new_value: f32, old_value: Option) -> Option { - let new_value = - if self.deadzone_lowerbound <= new_value && new_value <= self.deadzone_upperbound { - 0.0 - } else if new_value >= self.livezone_upperbound { - 1.0 - } else if new_value <= self.livezone_lowerbound { - -1.0 - } else { - new_value - }; - - if let Some(old_value) = old_value { - if (new_value - old_value).abs() <= self.threshold { - return None; - } + /// Clamps the `raw_value` according to the `AxisSettings`. + fn clamp(&self, new_value: f32) -> f32 { + if self.deadzone_lowerbound <= new_value && new_value <= self.deadzone_upperbound { + 0.0 + } else if new_value >= self.livezone_upperbound { + 1.0 + } else if new_value <= self.livezone_lowerbound { + -1.0 + } else { + new_value } + } + + /// Determines whether the change from `old_value` to `new_value` should + /// be registered as a change, according to the `AxisSettings`. + fn should_register_change(&self, new_value: f32, old_value: Option) -> bool { + if old_value.is_none() { + return true; + } + + f32::abs(new_value - old_value.unwrap()) > self.threshold + } + + /// Filters the `new_value` based on the `old_value`, according to the `AxisSettings`. + /// + /// Returns the `AxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, + /// and `None` otherwise. + fn filter(&self, new_value: f32, old_value: Option) -> Option { + let new_value = self.clamp(new_value); - Some(new_value) + if self.should_register_change(new_value, old_value) { + return Some(new_value); + } + None } } @@ -1069,7 +1020,7 @@ impl AxisSettings { /// /// ## Updating /// -/// The current value of a button is received through the [`GamepadEvent`]s or [`GamepadEventRaw`]s. +/// The current value of a button is received through the [RawGamepadButtonChangedEvent]. #[derive(Debug, Clone, Reflect, FromReflect)] #[reflect(Debug, Default)] pub struct ButtonAxisSettings { @@ -1092,59 +1043,47 @@ impl Default for ButtonAxisSettings { } impl ButtonAxisSettings { - /// Filters the `new_value` according to the specified settings. + /// Clamps the `raw_value` according to the specified settings. /// - /// If the `new_value` is: + /// If the `raw_value` is: /// - lower than or equal to `low` it will be rounded to 0.0. /// - higher than or equal to `high` it will be rounded to 1.0. /// - Otherwise it will not be rounded. + fn clamp(&self, raw_value: f32) -> f32 { + if raw_value <= self.low { + return 0.0; + } + if raw_value >= self.high { + return 1.0; + } + + raw_value + } + + /// Determines whether the change from an `old_value` to a `new_value` should + /// be registered as a change event, according to the specified settings. + fn should_register_change(&self, new_value: f32, old_value: Option) -> bool { + if old_value.is_none() { + return true; + } + + f32::abs(new_value - old_value.unwrap()) > self.threshold + } + + /// Filters the `new_value` based on the `old_value`, according to the `ButtonAxisSettings`. /// - /// If the difference between the calculated value and the `old_value` is lower or - /// equal to the `threshold`, [`None`] will be returned. + /// Returns the `ButtonAxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, + /// and `None` otherwise. fn filter(&self, new_value: f32, old_value: Option) -> Option { - let new_value = if new_value <= self.low { - 0.0 - } else if new_value >= self.high { - 1.0 - } else { - new_value - }; + let new_value = self.clamp(new_value); - if let Some(old_value) = old_value { - if (new_value - old_value).abs() <= self.threshold { - return None; - } + if self.should_register_change(new_value, old_value) { + return Some(new_value); } - - Some(new_value) + None } } -/// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. -/// -/// ## Note -/// -/// Whenever a [`Gamepad`] connects or disconnects, an information gets printed to the console using the [`info!`] macro. -// pub fn gamepad_connection_system( -// mut gamepads: ResMut, -// mut gamepad_event: EventReader, -// ) { -// for event in gamepad_event.iter() { -// match &event.event_type { -// GamepadEventType::Connected(info) => { -// gamepads.register(event.gamepad, info.clone()); -// info!("{:?} Connected", event.gamepad); -// } - -// GamepadEventType::Disconnected => { -// gamepads.deregister(event.gamepad); -// info!("{:?} Disconnected", event.gamepad); -// } -// _ => (), -// } -// } -// } - /// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. /// /// ## Note @@ -1212,6 +1151,15 @@ pub struct GamepadConnectionEvent { pub connection: GamepadConnection, } +impl GamepadConnectionEvent { + pub fn new(gamepad: Gamepad, connection: GamepadConnection) -> Self { + Self { + gamepad, + connection, + } + } +} + #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1221,10 +1169,20 @@ pub struct GamepadConnectionEvent { )] pub struct RawGamepadAxisChangedEvent { pub gamepad: Gamepad, - pub axis: GamepadAxis, + pub axis_type: GamepadAxisType, pub unfiltered_value: f32, } +impl RawGamepadAxisChangedEvent { + pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType, value: f32) -> Self { + Self { + gamepad, + axis_type, + unfiltered_value: value, + } + } +} + #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1234,10 +1192,24 @@ pub struct RawGamepadAxisChangedEvent { )] pub struct GamepadAxisChangedEvent { pub gamepad: Gamepad, - pub axis: GamepadAxis, + pub axis_type: GamepadAxisType, pub value: f32, } +impl GamepadAxisChangedEvent { + pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType, value: f32) -> Self { + Self { + gamepad, + axis_type, + value, + } + } +} + +/// Raw event indicating that the "value" of a button has changed. +/// This event is processed by the `gamepad_raw_button_event_system` +/// to generate a [GamepadButtonEvent] if the button was just pressed +/// or released. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1247,10 +1219,25 @@ pub struct GamepadAxisChangedEvent { )] pub struct RawGamepadButtonChangedEvent { pub gamepad: Gamepad, - pub button: GamepadButton, + pub button_type: GamepadButtonType, pub unfiltered_value: f32, } +impl RawGamepadButtonChangedEvent { + pub fn new(gamepad: Gamepad, button_type: GamepadButtonType, value: f32) -> Self { + Self { + gamepad, + button_type, + unfiltered_value: value, + } + } +} + +/// Gamepad event for button pressed and button released events. +/// +/// When a button is pressed, `button_state == ButtonState::Pressed` +/// indicating that the button was just pressed. Similarly for when a +/// button is released, `button_state == ButtonState::Released` #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1258,12 +1245,28 @@ pub struct RawGamepadButtonChangedEvent { derive(serde::Serialize, serde::Deserialize), reflect(Serialize, Deserialize) )] -pub struct GamepadButtonChangedEvent { +pub struct GamepadButtonEvent { pub gamepad: Gamepad, - pub button: GamepadButton, - pub value: f32, + pub button_type: GamepadButtonType, + pub button_state: ButtonState, } +impl GamepadButtonEvent { + pub fn new( + gamepad: Gamepad, + button_type: GamepadButtonType, + button_state: ButtonState, + ) -> Self { + Self { + gamepad, + button_type, + button_state, + } + } +} + +/// Handle [RawGamepadAxisChangedEvent]s, create [GamepadAxisChangedEvent]s, and update +/// the relevant `Input` and `Axis` values. pub fn gamepad_raw_axis_event_system( mut button_input: ResMut>, mut gamepad_axis: ResMut>, @@ -1272,142 +1275,60 @@ pub fn gamepad_raw_axis_event_system( settings: Res, ) { button_input.bypass_change_detection().clear(); - for RawGamepadAxisChangedEvent { - gamepad, - axis, - unfiltered_value, - } in raw_axis_events.iter() - { - if let Some(filtered_value) = settings - .get_axis_settings(*axis) - .filter(*unfiltered_value, gamepad_axis.get(*axis)) - { - gamepad_axis.set(*axis, filtered_value); - axis_events.send(GamepadAxisChangedEvent { - gamepad: *gamepad, - axis: *axis, - value: filtered_value, - }); + for axis_event in raw_axis_events.iter() { + let gamepad = axis_event.gamepad.to_owned(); + let axis = GamepadAxis::new(gamepad, axis_event.axis_type); + let axis_settings = settings.get_axis_settings(axis); + + let old_value = gamepad_axis.get(axis); + + if let Some(filtered_value) = axis_settings.filter(axis_event.unfiltered_value, old_value) { + gamepad_axis.set(axis, filtered_value); + axis_events.send(GamepadAxisChangedEvent::new( + gamepad, + axis_event.axis_type, + filtered_value, + )); } } } +/// Handle [RawGamepadButtonChangedEvent]s, create [GamepadButtonEvent]s, and update +/// the relevant `Input` and `Axis` values. pub fn gamepad_raw_button_event_system( mut raw_button_events: EventReader, - mut button_events: EventWriter, + mut button_events: EventWriter, mut button_input: ResMut>, mut button_axis: ResMut>, settings: Res, ) { button_input.bypass_change_detection().clear(); - for RawGamepadButtonChangedEvent { - gamepad, - button, - unfiltered_value, - } in raw_button_events.iter() - { - if let Some(filtered_value) = settings - .get_button_axis_settings(*button) - .filter(*unfiltered_value, button_axis.get(*button)) - { - button_axis.set(*button, filtered_value); - button_events.send(GamepadButtonChangedEvent { - gamepad: *gamepad, - button: *button, - value: filtered_value, - }); - } - - let button_property = settings.get_button_settings(*button); - if button_property.is_released(*unfiltered_value) { - button_input.release(*button); - } else if button_property.is_pressed(*unfiltered_value) { - button_input.press(*button); - } + for button_event in raw_button_events.iter() { + let gamepad = button_event.gamepad.to_owned(); + let button = GamepadButton::new(gamepad, button_event.button_type); + let raw_value = button_event.unfiltered_value; + let new_value = settings.get_button_axis_settings(button).clamp(raw_value); + + button_axis.set(button, new_value); + let button_property = settings.get_button_settings(button); + if button_property.is_released(new_value) { + button_input.release(button); + button_events.send(GamepadButtonEvent::new( + gamepad, + button_event.button_type, + ButtonState::Released, + )); + } else if button_property.is_pressed(new_value) { + button_input.press(button); + button_events.send(GamepadButtonEvent::new( + gamepad, + button_event.button_type, + ButtonState::Pressed, + )); + }; } } -/// Modifies the gamepad resources and sends out gamepad events. -/// -/// The resources [`Input`], [`Axis`], and [`Axis`] are updated -/// and the [`GamepadEvent`]s are sent according to the received [`GamepadEventRaw`]s respecting the [`GamepadSettings`]. -/// -/// ## Differences -/// -/// The main difference between the events and the resources is that the latter allows you to check specific -/// buttons or axes, rather than reading the events one at a time. This is done through convenient functions -/// like [`Input::pressed`], [`Input::just_pressed`], [`Input::just_released`], and [`Axis::get`]. -// pub fn gamepad_event_system( -// mut button_input: ResMut>, -// mut axis: ResMut>, -// mut button_axis: ResMut>, -// mut raw_events: EventReader, -// mut events: EventWriter, -// settings: Res, -// ) { -// button_input.bypass_change_detection().clear(); -// for event in raw_events.iter() { -// match &event.event_type { -// GamepadEventType::Connected(_) => { -// events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); -// for button_type in &ALL_BUTTON_TYPES { -// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); -// button_input.reset(gamepad_button); -// button_axis.set(gamepad_button, 0.0); -// } -// for axis_type in &ALL_AXIS_TYPES { -// axis.set(GamepadAxis::new(event.gamepad, *axis_type), 0.0); -// } -// } -// GamepadEventType::Disconnected => { -// events.send(GamepadEvent::new(event.gamepad, event.event_type.clone())); -// for button_type in &ALL_BUTTON_TYPES { -// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); -// button_input.reset(gamepad_button); -// button_axis.remove(gamepad_button); -// } -// for axis_type in &ALL_AXIS_TYPES { -// axis.remove(GamepadAxis::new(event.gamepad, *axis_type)); -// } -// } -// GamepadEventType::AxisChanged(axis_type, value) => { -// let gamepad_axis = GamepadAxis::new(event.gamepad, *axis_type); -// if let Some(filtered_value) = settings -// .get_axis_settings(gamepad_axis) -// .filter(*value, axis.get(gamepad_axis)) -// { -// axis.set(gamepad_axis, filtered_value); -// events.send(GamepadEvent::new( -// event.gamepad, -// GamepadEventType::AxisChanged(*axis_type, filtered_value), -// )); -// } -// } -// GamepadEventType::ButtonChanged(button_type, value) => { -// let gamepad_button = GamepadButton::new(event.gamepad, *button_type); -// if let Some(filtered_value) = settings -// .get_button_axis_settings(gamepad_button) -// .filter(*value, button_axis.get(gamepad_button)) -// { -// button_axis.set(gamepad_button, filtered_value); -// events.send(GamepadEvent::new( -// event.gamepad, -// GamepadEventType::ButtonChanged(*button_type, filtered_value), -// )); -// } - -// let button_property = settings.get_button_settings(gamepad_button); -// if button_property.is_released(*value) { -// button_input.release(gamepad_button); -// } else if button_property.is_pressed(*value) { -// button_input.press(gamepad_button); -// } -// } -// _ => (), -// } -// } -// } - /// An array of every [`GamepadButtonType`] variant. const ALL_BUTTON_TYPES: [GamepadButtonType; 19] = [ GamepadButtonType::South, diff --git a/crates/bevy_input/src/input.rs b/crates/bevy_input/src/input.rs index 25c0dd9b7f61c..3d1a1ecf5a9ad 100644 --- a/crates/bevy_input/src/input.rs +++ b/crates/bevy_input/src/input.rs @@ -7,17 +7,6 @@ use std::hash::Hash; #[allow(unused_imports)] use bevy_ecs::schedule::State; -// type PressableInput = Copy + Eq + Hash + Send + Sync + 'static; - -pub trait PressableInputEvent { - fn just_pressed(&self) -> bool; - fn just_released(&self) -> bool; -} - -// pub trait PressableInputValue { -// fn get_value(&self) -> T; -// } - /// A "press-able" input of type `T`. /// /// ## Usage @@ -55,7 +44,6 @@ pub trait PressableInputEvent { #[derive(Debug, Clone, Resource, Reflect)] #[reflect(Default)] pub struct Input { - // : PressableInput> { /// A collection of every button that is currently being pressed. pressed: HashSet, /// A collection of every button that has just been pressed. diff --git a/crates/bevy_input/src/keyboard.rs b/crates/bevy_input/src/keyboard.rs index 15ce329d5a395..021646015be7c 100644 --- a/crates/bevy_input/src/keyboard.rs +++ b/crates/bevy_input/src/keyboard.rs @@ -30,16 +30,6 @@ pub struct KeyboardInput { pub state: ButtonState, } -// impl PressableInputEvent for KeyboardInput { -// fn just_pressed(&self) -> bool { -// self.state.is_pressed() -// } - -// fn just_released(&self) -> bool { -// self.state.is_released() -// } -// } - /// Updates the [`Input`] resource with the latest [`KeyboardInput`] events. /// /// ## Differences diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 2b4ae5060af2a..d984a3a5090fd 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -34,8 +34,8 @@ use touch::{touch_screen_input_system, ForceTouch, TouchInput, TouchPhase, Touch use gamepad::{ gamepad_connection_system, gamepad_raw_axis_event_system, gamepad_raw_button_event_system, AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, - GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonChangedEvent, - GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, + GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonEvent, GamepadButtonType, + GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, }; @@ -73,7 +73,7 @@ impl Plugin for InputPlugin { .add_event::() .add_event::() .add_event::() - .add_event::() + .add_event::() .add_event::() .init_resource::() .init_resource::() @@ -86,11 +86,11 @@ impl Plugin for InputPlugin { ) .add_system_to_stage( CoreStage::PreUpdate, - gamepad_raw_axis_event_system.after(InputSystem), + gamepad_raw_axis_event_system.label(InputSystem), ) .add_system_to_stage( CoreStage::PreUpdate, - gamepad_connection_system.after(InputSystem), + gamepad_connection_system.label(InputSystem), ) // touch .add_event::() @@ -123,9 +123,6 @@ impl Plugin for InputPlugin { // Register gamepad types app.register_type::() .register_type::() - // .register_type::() - // .register_type::() - // .register_type::() .register_type::() .register_type::() .register_type::() @@ -154,8 +151,4 @@ impl ButtonState { pub fn is_pressed(&self) -> bool { matches!(self, ButtonState::Pressed) } - - pub fn is_released(&self) -> bool { - matches!(self, ButtonState::Released) - } } diff --git a/crates/bevy_input/src/mouse.rs b/crates/bevy_input/src/mouse.rs index 022ba82cd963e..bf86ed55b22ea 100644 --- a/crates/bevy_input/src/mouse.rs +++ b/crates/bevy_input/src/mouse.rs @@ -28,16 +28,6 @@ pub struct MouseButtonInput { pub state: ButtonState, } -// impl PressableInputEvent for MouseButtonInput { -// fn just_pressed(&self) -> bool { -// self.state.is_pressed() -// } - -// fn just_released(&self) -> bool { -// self.state.is_released() -// } -// } - /// A button on a mouse device. /// /// ## Usage From 4b859e92530a384fcaf0c7ae16e0408fef5318b8 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Thu, 15 Dec 2022 20:32:31 -0500 Subject: [PATCH 06/14] _ --- crates/bevy_app/src/app.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 5497230ed9f73..d88a82059126c 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -122,7 +122,6 @@ impl App { /// Creates a new [`App`] with some default structure to enable core engine features. /// This is the preferred constructor for most use cases. pub fn new() -> App { - println!("THIS IS A TEST VERSION"); App::default() } From 4e2cd1451ec60dea67dd4cba1cb44cc14a424666 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sun, 25 Dec 2022 19:21:47 -0700 Subject: [PATCH 07/14] Removed unused functions --- crates/bevy_input/src/gamepad.rs | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 329f1f4f529da..8805309bd76d2 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1059,29 +1059,6 @@ impl ButtonAxisSettings { raw_value } - - /// Determines whether the change from an `old_value` to a `new_value` should - /// be registered as a change event, according to the specified settings. - fn should_register_change(&self, new_value: f32, old_value: Option) -> bool { - if old_value.is_none() { - return true; - } - - f32::abs(new_value - old_value.unwrap()) > self.threshold - } - - /// Filters the `new_value` based on the `old_value`, according to the `ButtonAxisSettings`. - /// - /// Returns the `ButtonAxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, - /// and `None` otherwise. - fn filter(&self, new_value: f32, old_value: Option) -> Option { - let new_value = self.clamp(new_value); - - if self.should_register_change(new_value, old_value) { - return Some(new_value); - } - None - } } /// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. From a28e8ee7768039dc972d8e8fe5a2219e3e42a8f6 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sun, 25 Dec 2022 20:15:00 -0700 Subject: [PATCH 08/14] Updated the examples with the new events --- examples/input/gamepad_input_events.rs | 43 +++++++++++----------- examples/tools/gamepad_viewer.rs | 50 +++++++++++++------------- 2 files changed, 45 insertions(+), 48 deletions(-) diff --git a/examples/input/gamepad_input_events.rs b/examples/input/gamepad_input_events.rs index 3d33a0e32b138..0f1d64d5c7460 100644 --- a/examples/input/gamepad_input_events.rs +++ b/examples/input/gamepad_input_events.rs @@ -1,7 +1,7 @@ //! Iterates and prints gamepad input and connection events. use bevy::{ - input::gamepad::{GamepadEvent, GamepadEventType}, + input::gamepad::{GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnectionEvent}, prelude::*, }; @@ -12,27 +12,24 @@ fn main() { .run(); } -fn gamepad_events(mut gamepad_event: EventReader) { - for event in gamepad_event.iter() { - match event.event_type { - GamepadEventType::Connected(_) => { - info!("{:?} Connected", event.gamepad); - } - GamepadEventType::Disconnected => { - info!("{:?} Disconnected", event.gamepad); - } - GamepadEventType::ButtonChanged(button_type, value) => { - info!( - "{:?} of {:?} is changed to {}", - button_type, event.gamepad, value - ); - } - GamepadEventType::AxisChanged(axis_type, value) => { - info!( - "{:?} of {:?} is changed to {}", - axis_type, event.gamepad, value - ); - } - } +fn gamepad_events( + mut gamepad_connection_events: EventReader, + mut gamepad_axis_events: EventReader, + mut gamepad_button_events: EventReader, +) { + for connection_event in gamepad_connection_events.iter() { + info!("{:?}", connection_event); + } + for axis_event in gamepad_axis_events.iter() { + info!( + "{:?} of {:?} is changed to {}", + axis_event.axis_type, axis_event.gamepad, axis_event.value + ); + } + for button_event in gamepad_button_events.iter() { + info!( + "{:?} of {:?} is changed to {}", + button_event.button_type, button_event.gamepad, button_event.value + ); } } diff --git a/examples/tools/gamepad_viewer.rs b/examples/tools/gamepad_viewer.rs index bbc59a9d31cb5..2f7a77a57c04b 100644 --- a/examples/tools/gamepad_viewer.rs +++ b/examples/tools/gamepad_viewer.rs @@ -3,7 +3,9 @@ use std::f32::consts::PI; use bevy::{ - input::gamepad::{GamepadButton, GamepadSettings}, + input::gamepad::{ + GamepadAxisChangedEvent, GamepadButton, GamepadButtonChangedEvent, GamepadSettings, + }, prelude::*, sprite::{MaterialMesh2dBundle, Mesh2dHandle}, }; @@ -468,42 +470,40 @@ fn update_buttons( } fn update_button_values( - mut events: EventReader, + mut events: EventReader, mut query: Query<(&mut Text, &TextWithButtonValue)>, ) { - for event in events.iter() { - if let GamepadEventType::ButtonChanged(button_type, value) = event.event_type { - for (mut text, text_with_button_value) in query.iter_mut() { - if button_type == **text_with_button_value { - text.sections[0].value = format!("{value:.3}"); - } + for button_event in events.iter() { + for (mut text, text_with_button_value) in query.iter_mut() { + if button_event.button_type == **text_with_button_value { + text.sections[0].value = format!("{:.3}", button_event.value); } } } } fn update_axes( - mut events: EventReader, + mut axis_events: EventReader, mut query: Query<(&mut Transform, &MoveWithAxes)>, mut text_query: Query<(&mut Text, &TextWithAxes)>, ) { - for event in events.iter() { - if let GamepadEventType::AxisChanged(axis_type, value) = event.event_type { - for (mut transform, move_with) in query.iter_mut() { - if axis_type == move_with.x_axis { - transform.translation.x = value * move_with.scale; - } - if axis_type == move_with.y_axis { - transform.translation.y = value * move_with.scale; - } + for axis_event in axis_events.iter() { + let axis_type = axis_event.axis_type; + let value = axis_event.value; + for (mut transform, move_with) in query.iter_mut() { + if axis_type == move_with.x_axis { + transform.translation.x = value * move_with.scale; } - for (mut text, text_with_axes) in text_query.iter_mut() { - if axis_type == text_with_axes.x_axis { - text.sections[0].value = format!("{value:.3}"); - } - if axis_type == text_with_axes.y_axis { - text.sections[2].value = format!("{value:.3}"); - } + if axis_type == move_with.y_axis { + transform.translation.y = value * move_with.scale; + } + } + for (mut text, text_with_axes) in text_query.iter_mut() { + if axis_type == text_with_axes.x_axis { + text.sections[0].value = format!("{value:.3}"); + } + if axis_type == text_with_axes.y_axis { + text.sections[2].value = format!("{value:.3}"); } } } From 4b9a0ca6d346f21983b81d81e219474a469e5ae4 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sun, 25 Dec 2022 20:15:27 -0700 Subject: [PATCH 09/14] Updated docs + comments + lints --- crates/bevy_input/src/gamepad.rs | 209 +++++++++++-------------------- crates/bevy_input/src/lib.rs | 6 +- 2 files changed, 73 insertions(+), 142 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 8805309bd76d2..aab2a13d3c288 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -1,4 +1,4 @@ -use crate::{Axis, ButtonState, Input}; +use crate::{Axis, Input}; use bevy_ecs::event::{EventReader, EventWriter}; use bevy_ecs::{ change_detection::DetectChanges, @@ -145,120 +145,12 @@ impl Gamepads { } } -/// An event of a [`Gamepad`]. -/// -/// This event is the translated version of the [`GamepadEventRaw`]. It is available to -/// the end user and can be used for game logic. -/// -/// ## Differences -/// -/// The difference between the [`GamepadEventRaw`] and the [`GamepadEvent`] is that the -/// former respects user defined [`GamepadSettings`] for the gamepad inputs when translating it -/// to the latter. The former also updates the [`Input`], [`Axis`], -/// and [`Axis`] resources accordingly. -/// -/// ## Gamepad input mocking -/// -/// When mocking gamepad input, use [`GamepadEventRaw`]s instead of [`GamepadEvent`]s. -/// Otherwise [`GamepadSettings`] won't be respected and the [`Input`], -/// [`Axis`], and [`Axis`] resources won't be updated correctly. -/// -/// An example for gamepad input mocking can be seen in the documentation of the [`GamepadEventRaw`]. - -/// A raw event of a [`Gamepad`]. -/// -/// This event is the translated version of the `EventType` from the `GilRs` crate. -/// It is available to the end user and can be used for game logic. -/// -/// ## Differences -/// -/// The difference between the `EventType` from the `GilRs` crate and the [`GamepadEventRaw`] -/// is that the latter has less events, because the button pressing logic is handled through the generic -/// [`Input`] instead of through events. -/// -/// The difference between the [`GamepadEventRaw`] and the [`GamepadEvent`] can be seen in the documentation -/// of the [`GamepadEvent`]. -/// -/// ## Gamepad input mocking -/// -/// The following example showcases how to mock gamepad input by manually sending [`GamepadEventRaw`]s. -/// -/// ``` -/// # use bevy_input::prelude::*; -/// # use bevy_input::InputPlugin; -/// # use bevy_input::gamepad::{GamepadConnectionEvent, GamepadConnection, RawGamepadButtonChangedEvent, GamepadInfo}; -/// # use bevy_app::prelude::*; -/// # use bevy_ecs::prelude::*; -/// #[derive(Resource)] -/// struct MyResource(bool); -/// -/// // This system sets the bool inside `MyResource` to `true` if the `South` button of the first gamepad is pressed. -/// fn change_resource_on_gamepad_button_press( -/// mut my_resource: ResMut, -/// gamepads: Res, -/// button_inputs: ResMut>, -/// ) { -/// let gamepad = gamepads.iter().next().unwrap(); -/// let gamepad_button = GamepadButton::new(gamepad, GamepadButtonType::South); -/// -/// my_resource.0 = button_inputs.pressed(gamepad_button); -/// } -/// -/// // Create our app. -/// let mut app = App::new(); -/// -/// // Add the input plugin and the system/resource we want to test. -/// app.add_plugin(InputPlugin) -/// .insert_resource(MyResource(false)) -/// .add_system(change_resource_on_gamepad_button_press); -/// -/// // Define our dummy gamepad input data. -/// let gamepad = Gamepad::new(0); -/// let button_type = GamepadButtonType::South; -/// -/// // Send the gamepad connected event to mark our gamepad as connected. -/// // This updates the `Gamepads` resource accordingly. -/// let info = GamepadInfo { name: "Mock Gamepad".into() }; -/// app.world.send_event(GamepadConnectionEvent::new(gamepad, GamepadConnection::Connected(info))); -/// -/// // Send the gamepad input event to mark the `South` gamepad button as pressed. -/// // This updates the `Input` resource accordingly. -/// app.world.send_event(RawGamepadButtonChangedEvent::new( -/// gamepad, -/// button_type, -/// 1.0, -/// )); -/// -/// // Advance the execution of the schedule by a single cycle. -/// app.update(); -/// -/// // At this point you can check if your game logic corresponded correctly to the gamepad input. -/// // In this example we are checking if the bool in `MyResource` was updated from `false` to `true`. -/// assert!(app.world.resource::().0); -/// -/// // Send the gamepad input event to mark the `South` gamepad button as released. -/// // This updates the `Input` resource accordingly. -/// app.world.send_event(RawGamepadButtonChangedEvent::new( -/// gamepad, -/// button_type, -/// 0.0 -/// )); -/// -/// // Advance the execution of the schedule by another cycle. -/// app.update(); -/// -/// // Check if the bool in `MyResource` was updated from `true` to `false`. -/// assert!(!app.world.resource::().0); -/// # -/// # bevy_ecs::system::assert_is_system(change_resource_on_gamepad_button_press); -/// ``` - /// A type of a [`GamepadButton`]. /// /// ## Usage /// /// This is used to determine which button has changed its value when receiving a -/// [`GamepadEventType::ButtonChanged`]. It is also used in the [`GamepadButton`] +/// [`RawGamepadButtonChangedEvent`]. It is also used in the [`GamepadButton`] /// which in turn is used to create the [`Input`] or /// [`Axis`] `bevy` resources. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] @@ -1020,7 +912,7 @@ impl AxisSettings { /// /// ## Updating /// -/// The current value of a button is received through the [RawGamepadButtonChangedEvent]. +/// The current value of a button is received through the [`RawGamepadButtonChangedEvent`]. #[derive(Debug, Clone, Reflect, FromReflect)] #[reflect(Debug, Default)] pub struct ButtonAxisSettings { @@ -1059,6 +951,29 @@ impl ButtonAxisSettings { raw_value } + + /// Determines whether the change from an `old_value` to a `new_value` should + /// be registered as a change event, according to the specified settings. + fn should_register_change(&self, new_value: f32, old_value: Option) -> bool { + if old_value.is_none() { + return true; + } + + f32::abs(new_value - old_value.unwrap()) > self.threshold + } + + /// Filters the `new_value` based on the `old_value`, according to the `ButtonAxisSettings`. + /// + /// Returns the `ButtonAxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, + /// and `None` otherwise. + fn filter(&self, new_value: f32, old_value: Option) -> Option { + let new_value = self.clamp(new_value); + + if self.should_register_change(new_value, old_value) { + return Some(new_value); + } + None + } } /// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. @@ -1104,6 +1019,7 @@ pub fn gamepad_connection_system( } } } + #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1116,6 +1032,8 @@ pub enum GamepadConnection { Disconnected, } +/// A Gamepad connection event. Created when a connection to a gamepad +/// is established and when a gamepad is disconnected. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1124,7 +1042,9 @@ pub enum GamepadConnection { reflect(Serialize, Deserialize) )] pub struct GamepadConnectionEvent { + /// The gamepad whose connection status changed. pub gamepad: Gamepad, + /// The change in the gamepads connection. pub connection: GamepadConnection, } @@ -1135,8 +1055,20 @@ impl GamepadConnectionEvent { connection, } } + + pub fn connected(&self) -> bool { + matches!(self.connection, GamepadConnection::Connected(_)) + } + + pub fn disconnected(&self) -> bool { + !self.connected() + } } +/// Gamepad axis changed event, used internally to create a [`GamepadAxisChangedEvent`] +/// and update `Input` resources in the `gamepad_raw_axis_event_system`. The +/// difference between [`RawGamepadAxisChangedEvent`] and [`GamepadAxisChangedEvent`] +/// is that the latters axis "value" is filtered, based on a [`GamepadSettings`]. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1185,8 +1117,8 @@ impl GamepadAxisChangedEvent { /// Raw event indicating that the "value" of a button has changed. /// This event is processed by the `gamepad_raw_button_event_system` -/// to generate a [GamepadButtonEvent] if the button was just pressed -/// or released. +/// to generate a [`GamepadButtonChangedEvent`], if the change passes +/// a the [`GamepadSettings`] filter. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1222,27 +1154,23 @@ impl RawGamepadButtonChangedEvent { derive(serde::Serialize, serde::Deserialize), reflect(Serialize, Deserialize) )] -pub struct GamepadButtonEvent { +pub struct GamepadButtonChangedEvent { pub gamepad: Gamepad, pub button_type: GamepadButtonType, - pub button_state: ButtonState, + pub value: f32, } -impl GamepadButtonEvent { - pub fn new( - gamepad: Gamepad, - button_type: GamepadButtonType, - button_state: ButtonState, - ) -> Self { +impl GamepadButtonChangedEvent { + pub fn new(gamepad: Gamepad, button_type: GamepadButtonType, value: f32) -> Self { Self { gamepad, button_type, - button_state, + value, } } } -/// Handle [RawGamepadAxisChangedEvent]s, create [GamepadAxisChangedEvent]s, and update +/// Handle [`RawGamepadAxisChangedEvent`]s, create [`GamepadAxisChangedEvent`]s, and update /// the relevant `Input` and `Axis` values. pub fn gamepad_raw_axis_event_system( mut button_input: ResMut>, @@ -1270,11 +1198,11 @@ pub fn gamepad_raw_axis_event_system( } } -/// Handle [RawGamepadButtonChangedEvent]s, create [GamepadButtonEvent]s, and update +/// Handle [`RawGamepadButtonChangedEvent`]s, create [`GamepadButtonChangedEvent`]s, and update /// the relevant `Input` and `Axis` values. pub fn gamepad_raw_button_event_system( mut raw_button_events: EventReader, - mut button_events: EventWriter, + mut button_events: EventWriter, mut button_input: ResMut>, mut button_axis: ResMut>, settings: Res, @@ -1283,26 +1211,29 @@ pub fn gamepad_raw_button_event_system( for button_event in raw_button_events.iter() { let gamepad = button_event.gamepad.to_owned(); let button = GamepadButton::new(gamepad, button_event.button_type); - let raw_value = button_event.unfiltered_value; - let new_value = settings.get_button_axis_settings(button).clamp(raw_value); - - button_axis.set(button, new_value); + let button_axis_settings = settings.get_button_axis_settings(button); + let new_value = button_axis_settings.clamp(button_event.unfiltered_value); + let old_value = button_axis.get(button); let button_property = settings.get_button_settings(button); - if button_property.is_released(new_value) { + + // Check if the button is pressed or released + let was_pressed = old_value.is_some() && button_property.is_pressed(old_value.unwrap()); + if was_pressed && button_property.is_released(new_value) { button_input.release(button); - button_events.send(GamepadButtonEvent::new( - gamepad, - button_event.button_type, - ButtonState::Released, - )); } else if button_property.is_pressed(new_value) { button_input.press(button); - button_events.send(GamepadButtonEvent::new( + }; + + button_axis.set(button, new_value); + + // Check if the change should be registered + if button_axis_settings.filter(new_value, old_value).is_some() { + button_events.send(GamepadButtonChangedEvent::new( gamepad, - button_event.button_type, - ButtonState::Pressed, + button.button_type, + new_value, )); - }; + } } } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index d984a3a5090fd..e34d94b4103c2 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -34,8 +34,8 @@ use touch::{touch_screen_input_system, ForceTouch, TouchInput, TouchPhase, Touch use gamepad::{ gamepad_connection_system, gamepad_raw_axis_event_system, gamepad_raw_button_event_system, AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, - GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonEvent, GamepadButtonType, - GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, + GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonChangedEvent, + GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, }; @@ -73,7 +73,7 @@ impl Plugin for InputPlugin { .add_event::() .add_event::() .add_event::() - .add_event::() + .add_event::() .add_event::() .init_resource::() .init_resource::() From e4e23065c0e7871a2dada9e8caa284ad0a83028d Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sun, 25 Dec 2022 20:23:29 -0700 Subject: [PATCH 10/14] Lints --- crates/bevy_input/src/gamepad.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index aab2a13d3c288..caa7a25a2709e 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -65,8 +65,8 @@ use bevy_reflect::{ReflectDeserialize, ReflectSerialize}; /// ## Usage /// /// The primary way to access the individual connected gamepads is done through the [`Gamepads`] -/// `bevy` resource. It is also used inside of [`GamepadEvent`]s and [`GamepadEventRaw`]s to distinguish -/// which gamepad an event corresponds to. +/// `bevy` resource. It is also used inside of [`GamepadConnectionEvent`]s to correspond a gamepad +/// with a connection event. /// /// ## Note /// @@ -111,8 +111,7 @@ pub struct GamepadInfo { /// ## Updating /// /// The [`Gamepad`]s are registered and deregistered in the [`gamepad_connection_system`] -/// whenever a [`GamepadEventType::Connected`] or [`GamepadEventType::Disconnected`] -/// event is received. +/// whenever a [`GamepadConnectionEvent`] is received. #[derive(Resource, Default, Debug)] pub struct Gamepads { /// The collection of the connected [`Gamepad`]s. @@ -217,7 +216,8 @@ pub enum GamepadButtonType { /// /// ## Updating /// -/// The resources are updated inside of the [`gamepad_event_system`]. +/// The resources are updated inside of [`gamepad_raw_axis_event_system`] and +/// [`gamepad_raw_button_event_system`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( @@ -1066,7 +1066,7 @@ impl GamepadConnectionEvent { } /// Gamepad axis changed event, used internally to create a [`GamepadAxisChangedEvent`] -/// and update `Input` resources in the `gamepad_raw_axis_event_system`. The +/// and update `Input` resources in the [`gamepad_raw_axis_event_system`]. The /// difference between [`RawGamepadAxisChangedEvent`] and [`GamepadAxisChangedEvent`] /// is that the latters axis "value" is filtered, based on a [`GamepadSettings`]. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] @@ -1116,7 +1116,7 @@ impl GamepadAxisChangedEvent { } /// Raw event indicating that the "value" of a button has changed. -/// This event is processed by the `gamepad_raw_button_event_system` +/// This event is processed by the [`gamepad_raw_button_event_system`] /// to generate a [`GamepadButtonChangedEvent`], if the change passes /// a the [`GamepadSettings`] filter. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] From e5ae177017f15d2348574e136f50b0103222484a Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sat, 31 Dec 2022 20:10:12 -0700 Subject: [PATCH 11/14] Updated doc comments + created system set gamepad systems --- crates/bevy_input/src/gamepad.rs | 26 +++++++++++++++++--------- crates/bevy_input/src/lib.rs | 18 +++++++----------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index caa7a25a2709e..e3b1ef303e4f5 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -295,7 +295,8 @@ pub enum GamepadAxisType { /// /// ## Updating /// -/// The resource is updated inside of the gamepad event handling systems. +/// The resource is updated inside of the gamepad event handling systems, +/// [`gamepad_raw_button_event_system`] and [`gamepad_raw_axis_event_system`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( @@ -338,8 +339,9 @@ impl GamepadAxis { /// /// ## Note /// -/// The [`GamepadSettings`] are used inside of the gamepad event handling systems, but are never written to -/// inside of `bevy`. To modify these settings, mutate the corresponding resource. +/// The [`GamepadSettings`] are used inside of the gamepad event handling systems, +/// [`gamepad_raw_button_event_system`] and [`gamepad_raw_axis_event_system`], but +/// are never written to inside of `bevy`. To modify these settings, mutate the corresponding resource. #[derive(Resource, Default, Debug, Reflect, FromReflect)] #[reflect(Debug, Default)] pub struct GamepadSettings { @@ -885,7 +887,7 @@ impl AxisSettings { /// Filters the `new_value` based on the `old_value`, according to the `AxisSettings`. /// - /// Returns the `AxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, + /// Returns the [clamped](`AxisSettings::clamp`) `new_value` if the change exceeds the settings threshold, /// and `None` otherwise. fn filter(&self, new_value: f32, old_value: Option) -> Option { let new_value = self.clamp(new_value); @@ -964,8 +966,9 @@ impl ButtonAxisSettings { /// Filters the `new_value` based on the `old_value`, according to the `ButtonAxisSettings`. /// - /// Returns the `ButtonAxisSettings::clamp`ed `new_value` if the change exceeds the settings threshold, + /// Returns the [clamped](`ButtonAxisSettings::clamp`) `new_value` if the change exceeds the settings threshold, /// and `None` otherwise. + #[allow(unused)] fn filter(&self, new_value: f32, old_value: Option) -> Option { let new_value = self.clamp(new_value); @@ -976,7 +979,10 @@ impl ButtonAxisSettings { } } -/// Monitors gamepad connection and disconnection events and updates the [`Gamepads`] resource accordingly. +/// Handles [`GamepadConnectionEvent`]s and updates gamepad resources. +/// +/// Updates the [`Gamepads`] resource and resets and/or initializes +/// the [`Axis`] and [`Input`] resources. /// /// ## Note /// @@ -1066,8 +1072,9 @@ impl GamepadConnectionEvent { } /// Gamepad axis changed event, used internally to create a [`GamepadAxisChangedEvent`] -/// and update `Input` resources in the [`gamepad_raw_axis_event_system`]. The -/// difference between [`RawGamepadAxisChangedEvent`] and [`GamepadAxisChangedEvent`] +/// and update `Input` resources in the [`gamepad_raw_axis_event_system`]. +/// +/// The difference between [`RawGamepadAxisChangedEvent`] and [`GamepadAxisChangedEvent`] /// is that the latters axis "value" is filtered, based on a [`GamepadSettings`]. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] @@ -1116,6 +1123,7 @@ impl GamepadAxisChangedEvent { } /// Raw event indicating that the "value" of a button has changed. +/// /// This event is processed by the [`gamepad_raw_button_event_system`] /// to generate a [`GamepadButtonChangedEvent`], if the change passes /// a the [`GamepadSettings`] filter. @@ -1227,7 +1235,7 @@ pub fn gamepad_raw_button_event_system( button_axis.set(button, new_value); // Check if the change should be registered - if button_axis_settings.filter(new_value, old_value).is_some() { + if button_axis_settings.should_register_change(new_value, old_value) { button_events.send(GamepadButtonChangedEvent::new( gamepad, button.button_type, diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index e34d94b4103c2..66f9e8c14ad31 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -22,7 +22,7 @@ pub mod prelude { } use bevy_app::prelude::*; -use bevy_ecs::schedule::{IntoSystemDescriptor, SystemLabel}; +use bevy_ecs::schedule::{IntoSystemDescriptor, SystemLabel, SystemSet}; use bevy_reflect::{FromReflect, Reflect}; use keyboard::{keyboard_input_system, KeyCode, KeyboardInput, ScanCode}; use mouse::{ @@ -80,17 +80,13 @@ impl Plugin for InputPlugin { .init_resource::>() .init_resource::>() .init_resource::>() - .add_system_to_stage( - CoreStage::PreUpdate, - gamepad_raw_button_event_system.label(InputSystem), - ) - .add_system_to_stage( - CoreStage::PreUpdate, - gamepad_raw_axis_event_system.label(InputSystem), - ) - .add_system_to_stage( + .add_system_set_to_stage( CoreStage::PreUpdate, - gamepad_connection_system.label(InputSystem), + SystemSet::new() + .with_system(gamepad_raw_button_event_system) + .with_system(gamepad_raw_axis_event_system) + .with_system(gamepad_connection_system) + .label(InputSystem), ) // touch .add_event::() From cc4f334b67c5b65f5218e31484e8ae7e3809cd24 Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Sun, 1 Jan 2023 15:46:34 -0700 Subject: [PATCH 12/14] Removed allow(unused) in favour of having of using --- crates/bevy_input/src/gamepad.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index e3b1ef303e4f5..ed27b138e6471 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -966,10 +966,9 @@ impl ButtonAxisSettings { /// Filters the `new_value` based on the `old_value`, according to the `ButtonAxisSettings`. /// - /// Returns the [clamped](`ButtonAxisSettings::clamp`) `new_value` if the change exceeds the settings threshold, - /// and `None` otherwise. - #[allow(unused)] - fn filter(&self, new_value: f32, old_value: Option) -> Option { + /// Returns the clamped `new_value`, according to the [`ButtonAxisSettings`], if the change + /// exceeds the settings threshold, and `None` otherwise. + pub fn filter(&self, new_value: f32, old_value: Option) -> Option { let new_value = self.clamp(new_value); if self.should_register_change(new_value, old_value) { From c1cf73f8664ce37d2e186afbb56ed408c7c0394f Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Wed, 4 Jan 2023 20:52:17 -0700 Subject: [PATCH 13/14] Added back GamepadEvent, removed "Raw" versions of gamepad events, moved filtering to bevy_gilrs, updated docs --- crates/bevy_gilrs/src/gilrs_system.rs | 61 +++++--- crates/bevy_input/src/gamepad.rs | 208 +++++++++++--------------- crates/bevy_input/src/lib.rs | 18 +-- 3 files changed, 133 insertions(+), 154 deletions(-) diff --git a/crates/bevy_gilrs/src/gilrs_system.rs b/crates/bevy_gilrs/src/gilrs_system.rs index cbe95bfab8a45..de1d0afb3c733 100644 --- a/crates/bevy_gilrs/src/gilrs_system.rs +++ b/crates/bevy_gilrs/src/gilrs_system.rs @@ -1,11 +1,13 @@ use crate::converter::{convert_axis, convert_button, convert_gamepad_id}; use bevy_ecs::event::EventWriter; -use bevy_ecs::system::{NonSend, NonSendMut}; -use bevy_input::gamepad::GamepadInfo; +use bevy_ecs::system::{NonSend, NonSendMut, Res}; use bevy_input::gamepad::{ - GamepadConnection, GamepadConnectionEvent, RawGamepadAxisChangedEvent, - RawGamepadButtonChangedEvent, + GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnection, GamepadConnectionEvent, + GamepadSettings, }; +use bevy_input::gamepad::{GamepadEvent, GamepadInfo}; +use bevy_input::prelude::{GamepadAxis, GamepadButton}; +use bevy_input::Axis; use gilrs::{ev::filter::axis_dpad_to_button, EventType, Filter, Gilrs}; pub fn gilrs_event_startup_system( @@ -26,9 +28,10 @@ pub fn gilrs_event_startup_system( pub fn gilrs_event_system( mut gilrs: NonSendMut, - mut axis_events: EventWriter, - mut button_events: EventWriter, - mut connection_events: EventWriter, + mut events: EventWriter, + gamepad_axis: Res>, + gamepad_buttons: Res>, + gamepad_settings: Res, ) { while let Some(gilrs_event) = gilrs .next_event() @@ -44,27 +47,39 @@ pub fn gilrs_event_system( name: pad.name().into(), }; - connection_events.send(GamepadConnectionEvent { - gamepad, - connection: GamepadConnection::Connected(info), - }); + events.send( + GamepadConnectionEvent::new(gamepad, GamepadConnection::Connected(info)).into(), + ); } - EventType::Disconnected => connection_events.send(GamepadConnectionEvent { - gamepad, - connection: GamepadConnection::Disconnected, - }), - EventType::ButtonChanged(gilrs_button, value, _) => { + EventType::Disconnected => events + .send(GamepadConnectionEvent::new(gamepad, GamepadConnection::Disconnected).into()), + EventType::ButtonChanged(gilrs_button, raw_value, _) => { if let Some(button_type) = convert_button(gilrs_button) { - button_events.send(RawGamepadButtonChangedEvent::new( - gamepad, - button_type, - value, - )); + let button = GamepadButton::new(gamepad, button_type); + let old_value = gamepad_buttons.get(button); + let button_settings = gamepad_settings.get_button_axis_settings(button); + + // Only send events that pass the user-defined change threshold + if let Some(filtered_value) = button_settings.filter(raw_value, old_value) { + events.send( + GamepadButtonChangedEvent::new(gamepad, button_type, filtered_value) + .into(), + ); + } } } - EventType::AxisChanged(gilrs_axis, value, _) => { + EventType::AxisChanged(gilrs_axis, raw_value, _) => { if let Some(axis_type) = convert_axis(gilrs_axis) { - axis_events.send(RawGamepadAxisChangedEvent::new(gamepad, axis_type, value)); + let axis = GamepadAxis::new(gamepad, axis_type); + let old_value = gamepad_axis.get(axis); + let axis_settings = gamepad_settings.get_axis_settings(axis); + + // Only send events that pass the user-defined change threshold + if let Some(filtered_value) = axis_settings.filter(raw_value, old_value) { + events.send( + GamepadAxisChangedEvent::new(gamepad, axis_type, filtered_value).into(), + ); + } } } _ => (), diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index ed27b138e6471..a72c84f1b110e 100644 --- a/crates/bevy_input/src/gamepad.rs +++ b/crates/bevy_input/src/gamepad.rs @@ -149,7 +149,7 @@ impl Gamepads { /// ## Usage /// /// This is used to determine which button has changed its value when receiving a -/// [`RawGamepadButtonChangedEvent`]. It is also used in the [`GamepadButton`] +/// [`GamepadButtonChangedEvent`]. It is also used in the [`GamepadButton`] /// which in turn is used to create the [`Input`] or /// [`Axis`] `bevy` resources. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] @@ -212,12 +212,11 @@ pub enum GamepadButtonType { /// ## Usage /// /// It is used as the generic `T` value of an [`Input`] and [`Axis`] to create `bevy` resources. These -/// resources store the data of the buttons and axes of a gamepad and can be accessed inside of a system. +/// resources store the data of the buttons of a gamepad and can be accessed inside of a system. /// /// ## Updating /// -/// The resources are updated inside of [`gamepad_raw_axis_event_system`] and -/// [`gamepad_raw_button_event_system`]. +/// The gamepad button resources are updated inside of the [`gamepad_button_event_system`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( @@ -258,7 +257,7 @@ impl GamepadButton { /// ## Usage /// /// This is used to determine which axis has changed its value when receiving a -/// [`RawGamepadAxisChangedEvent`]. It is also used in the [`GamepadAxis`] +/// [`GamepadAxisChangedEvent`]. It is also used in the [`GamepadAxis`] /// which in turn is used to create the [`Axis`] `bevy` resource. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] @@ -290,13 +289,12 @@ pub enum GamepadAxisType { /// /// ## Usage /// -/// It is used as the generic `T` value of an [`Axis`] to create a `bevy` resource. This resource -/// stores the data of the axes of a gamepad and can be accessed inside of a system. +/// It is used as the generic `T` value of an [`Axis`] to create `bevy` resources. These +/// resources store the data of the axes of a gamepad and can be accessed inside of a system. /// /// ## Updating /// -/// The resource is updated inside of the gamepad event handling systems, -/// [`gamepad_raw_button_event_system`] and [`gamepad_raw_axis_event_system`]. +/// The gamepad axes resources are updated inside of the [`gamepad_axis_event_system`]. #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Reflect, FromReflect)] #[reflect(Debug, Hash, PartialEq)] #[cfg_attr( @@ -339,9 +337,9 @@ impl GamepadAxis { /// /// ## Note /// -/// The [`GamepadSettings`] are used inside of the gamepad event handling systems, -/// [`gamepad_raw_button_event_system`] and [`gamepad_raw_axis_event_system`], but -/// are never written to inside of `bevy`. To modify these settings, mutate the corresponding resource. +/// The [`GamepadSettings`] are used inside of `bevy_gilrs` to determine when raw gamepad events from `girls`, +/// should register as a [`GamepadEvent`]. Events that don't meet the change thresholds defined in [`GamepadSettings`] +/// will not register. To modify these settings, mutate the corresponding resource. #[derive(Resource, Default, Debug, Reflect, FromReflect)] #[reflect(Debug, Default)] pub struct GamepadSettings { @@ -863,7 +861,7 @@ impl AxisSettings { } /// Clamps the `raw_value` according to the `AxisSettings`. - fn clamp(&self, new_value: f32) -> f32 { + pub fn clamp(&self, new_value: f32) -> f32 { if self.deadzone_lowerbound <= new_value && new_value <= self.deadzone_upperbound { 0.0 } else if new_value >= self.livezone_upperbound { @@ -885,11 +883,11 @@ impl AxisSettings { f32::abs(new_value - old_value.unwrap()) > self.threshold } - /// Filters the `new_value` based on the `old_value`, according to the `AxisSettings`. + /// Filters the `new_value` based on the `old_value`, according to the [`AxisSettings`]. /// - /// Returns the [clamped](`AxisSettings::clamp`) `new_value` if the change exceeds the settings threshold, + /// Returns the clamped `new_value` if the change exceeds the settings threshold, /// and `None` otherwise. - fn filter(&self, new_value: f32, old_value: Option) -> Option { + pub fn filter(&self, new_value: f32, old_value: Option) -> Option { let new_value = self.clamp(new_value); if self.should_register_change(new_value, old_value) { @@ -914,7 +912,7 @@ impl AxisSettings { /// /// ## Updating /// -/// The current value of a button is received through the [`RawGamepadButtonChangedEvent`]. +/// The current value of a button is received through the [`GamepadButtonChangedEvent`]. #[derive(Debug, Clone, Reflect, FromReflect)] #[reflect(Debug, Default)] pub struct ButtonAxisSettings { @@ -1070,34 +1068,6 @@ impl GamepadConnectionEvent { } } -/// Gamepad axis changed event, used internally to create a [`GamepadAxisChangedEvent`] -/// and update `Input` resources in the [`gamepad_raw_axis_event_system`]. -/// -/// The difference between [`RawGamepadAxisChangedEvent`] and [`GamepadAxisChangedEvent`] -/// is that the latters axis "value" is filtered, based on a [`GamepadSettings`]. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -#[reflect(Debug, PartialEq)] -#[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), - reflect(Serialize, Deserialize) -)] -pub struct RawGamepadAxisChangedEvent { - pub gamepad: Gamepad, - pub axis_type: GamepadAxisType, - pub unfiltered_value: f32, -} - -impl RawGamepadAxisChangedEvent { - pub fn new(gamepad: Gamepad, axis_type: GamepadAxisType, value: f32) -> Self { - Self { - gamepad, - axis_type, - unfiltered_value: value, - } - } -} - #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1121,39 +1091,8 @@ impl GamepadAxisChangedEvent { } } -/// Raw event indicating that the "value" of a button has changed. -/// -/// This event is processed by the [`gamepad_raw_button_event_system`] -/// to generate a [`GamepadButtonChangedEvent`], if the change passes -/// a the [`GamepadSettings`] filter. -#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] -#[reflect(Debug, PartialEq)] -#[cfg_attr( - feature = "serialize", - derive(serde::Serialize, serde::Deserialize), - reflect(Serialize, Deserialize) -)] -pub struct RawGamepadButtonChangedEvent { - pub gamepad: Gamepad, - pub button_type: GamepadButtonType, - pub unfiltered_value: f32, -} - -impl RawGamepadButtonChangedEvent { - pub fn new(gamepad: Gamepad, button_type: GamepadButtonType, value: f32) -> Self { - Self { - gamepad, - button_type, - unfiltered_value: value, - } - } -} - -/// Gamepad event for button pressed and button released events. -/// -/// When a button is pressed, `button_state == ButtonState::Pressed` -/// indicating that the button was just pressed. Similarly for when a -/// button is released, `button_state == ButtonState::Released` +/// Gamepad event for when the "value" (amount of pressure) on the button +/// changes by an amount larger than the threshold defined in [`GamepadSettings`]. #[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] #[reflect(Debug, PartialEq)] #[cfg_attr( @@ -1177,69 +1116,94 @@ impl GamepadButtonChangedEvent { } } -/// Handle [`RawGamepadAxisChangedEvent`]s, create [`GamepadAxisChangedEvent`]s, and update -/// the relevant `Input` and `Axis` values. -pub fn gamepad_raw_axis_event_system( +/// Uses [`GamepadAxisChangedEvent`]s to update update the relevant `Input` and `Axis` values. +pub fn gamepad_axis_event_system( mut button_input: ResMut>, mut gamepad_axis: ResMut>, - mut raw_axis_events: EventReader, - mut axis_events: EventWriter, - settings: Res, + mut axis_events: EventReader, ) { button_input.bypass_change_detection().clear(); - for axis_event in raw_axis_events.iter() { - let gamepad = axis_event.gamepad.to_owned(); - let axis = GamepadAxis::new(gamepad, axis_event.axis_type); - let axis_settings = settings.get_axis_settings(axis); - - let old_value = gamepad_axis.get(axis); - - if let Some(filtered_value) = axis_settings.filter(axis_event.unfiltered_value, old_value) { - gamepad_axis.set(axis, filtered_value); - axis_events.send(GamepadAxisChangedEvent::new( - gamepad, - axis_event.axis_type, - filtered_value, - )); - } + for axis_event in axis_events.iter() { + let axis = GamepadAxis::new(axis_event.gamepad, axis_event.axis_type); + gamepad_axis.set(axis, axis_event.value); } } -/// Handle [`RawGamepadButtonChangedEvent`]s, create [`GamepadButtonChangedEvent`]s, and update -/// the relevant `Input` and `Axis` values. -pub fn gamepad_raw_button_event_system( - mut raw_button_events: EventReader, - mut button_events: EventWriter, +/// Uses [`GamepadButtonChangedEvent`]s to update update the relevant `Input` and `Axis` values. +pub fn gamepad_button_event_system( + mut button_events: EventReader, mut button_input: ResMut>, mut button_axis: ResMut>, settings: Res, ) { button_input.bypass_change_detection().clear(); - for button_event in raw_button_events.iter() { - let gamepad = button_event.gamepad.to_owned(); - let button = GamepadButton::new(gamepad, button_event.button_type); - let button_axis_settings = settings.get_button_axis_settings(button); - let new_value = button_axis_settings.clamp(button_event.unfiltered_value); - let old_value = button_axis.get(button); + for button_event in button_events.iter() { + let button = GamepadButton::new(button_event.gamepad, button_event.button_type); + let value = button_event.value; let button_property = settings.get_button_settings(button); - // Check if the button is pressed or released - let was_pressed = old_value.is_some() && button_property.is_pressed(old_value.unwrap()); - if was_pressed && button_property.is_released(new_value) { + if button_property.is_released(value) { + // We don't have to check if the button was previously pressed + // because that check is performed within Input::release() button_input.release(button); - } else if button_property.is_pressed(new_value) { + } else if button_property.is_pressed(value) { button_input.press(button); }; - button_axis.set(button, new_value); + button_axis.set(button, value); + } +} - // Check if the change should be registered - if button_axis_settings.should_register_change(new_value, old_value) { - button_events.send(GamepadButtonChangedEvent::new( - gamepad, - button.button_type, - new_value, - )); +/// A gamepad event. +/// +/// This event type is used over the [`GamepadConnectionEvent`], +/// [`GamepadButtonChangedEvent`] and [`GamepadAxisChangedEvent`] when +/// the in-frame relative ordering of events is important. +#[derive(Debug, Clone, PartialEq, Reflect, FromReflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub enum GamepadEvent { + Connection(GamepadConnectionEvent), + Button(GamepadButtonChangedEvent), + Axis(GamepadAxisChangedEvent), +} + +impl From for GamepadEvent { + fn from(value: GamepadConnectionEvent) -> Self { + Self::Connection(value) + } +} + +impl From for GamepadEvent { + fn from(value: GamepadButtonChangedEvent) -> Self { + Self::Button(value) + } +} + +impl From for GamepadEvent { + fn from(value: GamepadAxisChangedEvent) -> Self { + Self::Axis(value) + } +} + +/// Splits the [`GamepadEvent`] event stream into it's component events. +pub fn gamepad_event_system( + mut gamepad_events: EventReader, + mut connection_events: EventWriter, + mut button_events: EventWriter, + mut axis_events: EventWriter, +) { + for gamepad_event in gamepad_events.iter() { + match gamepad_event { + GamepadEvent::Connection(connection_event) => { + connection_events.send(connection_event.clone()); + } + GamepadEvent::Button(button_event) => button_events.send(button_event.clone()), + GamepadEvent::Axis(axis_event) => axis_events.send(axis_event.clone()), } } } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index 66f9e8c14ad31..fccc2027f56b4 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -32,11 +32,11 @@ use mouse::{ use touch::{touch_screen_input_system, ForceTouch, TouchInput, TouchPhase, Touches}; use gamepad::{ - gamepad_connection_system, gamepad_raw_axis_event_system, gamepad_raw_button_event_system, - AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, + gamepad_axis_event_system, gamepad_button_event_system, gamepad_connection_system, + gamepad_event_system, AxisSettings, ButtonAxisSettings, ButtonSettings, Gamepad, GamepadAxis, GamepadAxisChangedEvent, GamepadAxisType, GamepadButton, GamepadButtonChangedEvent, - GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadSettings, Gamepads, - RawGamepadAxisChangedEvent, RawGamepadButtonChangedEvent, + GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadEvent, GamepadSettings, + Gamepads, }; #[cfg(feature = "serialize")] @@ -70,11 +70,10 @@ impl Plugin for InputPlugin { mouse_button_input_system.label(InputSystem), ) // gamepad - .add_event::() - .add_event::() .add_event::() .add_event::() .add_event::() + .add_event::() .init_resource::() .init_resource::() .init_resource::>() @@ -83,9 +82,10 @@ impl Plugin for InputPlugin { .add_system_set_to_stage( CoreStage::PreUpdate, SystemSet::new() - .with_system(gamepad_raw_button_event_system) - .with_system(gamepad_raw_axis_event_system) - .with_system(gamepad_connection_system) + .with_system(gamepad_event_system) + .with_system(gamepad_button_event_system.after(gamepad_event_system)) + .with_system(gamepad_axis_event_system.after(gamepad_event_system)) + .with_system(gamepad_connection_system.after(gamepad_event_system)) .label(InputSystem), ) // touch From b2d5cdd4988ff7a86fb974f106217ba9b3f2d85f Mon Sep 17 00:00:00 2001 From: Devin Leamy Date: Thu, 5 Jan 2023 10:05:45 -0700 Subject: [PATCH 14/14] Extended example to showcase reading ordered events --- examples/input/gamepad_input_events.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/examples/input/gamepad_input_events.rs b/examples/input/gamepad_input_events.rs index 0f1d64d5c7460..d4d9725d0c444 100644 --- a/examples/input/gamepad_input_events.rs +++ b/examples/input/gamepad_input_events.rs @@ -1,7 +1,9 @@ //! Iterates and prints gamepad input and connection events. use bevy::{ - input::gamepad::{GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnectionEvent}, + input::gamepad::{ + GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnectionEvent, GamepadEvent, + }, prelude::*, }; @@ -9,6 +11,7 @@ fn main() { App::new() .add_plugins(DefaultPlugins) .add_system(gamepad_events) + .add_system(gamepad_ordered_events) .run(); } @@ -33,3 +36,16 @@ fn gamepad_events( ); } } + +// If you require in-frame relative event ordering, you can also read the `Gamepad` event +// stream directly. For standard use-cases, reading the events individually or using the +// `Input` or `Axis` resources is preferable. +fn gamepad_ordered_events(mut gamepad_events: EventReader) { + for gamepad_event in gamepad_events.iter() { + match gamepad_event { + GamepadEvent::Connection(connection_event) => info!("{:?}", connection_event), + GamepadEvent::Button(button_event) => info!("{:?}", button_event), + GamepadEvent::Axis(axis_event) => info!("{:?}", axis_event), + } + } +}