diff --git a/crates/bevy_input/src/gamepad.rs b/crates/bevy_input/src/gamepad.rs index 724bcb82b1cf1..2cf6d1cbceef2 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::{Event, EventReader, EventWriter}; use bevy_ecs::{ change_detection::DetectChangesMut, @@ -265,6 +265,21 @@ impl GamepadButton { } } +/// A gamepad button input event. +#[derive(Event, Debug, Clone, Copy, PartialEq, Eq, Reflect)] +#[reflect(Debug, PartialEq)] +#[cfg_attr( + feature = "serialize", + derive(serde::Serialize, serde::Deserialize), + reflect(Serialize, Deserialize) +)] +pub struct GamepadButtonInput { + /// The gamepad button assigned to the event. + pub button: GamepadButton, + /// The pressed state of the button. + pub state: ButtonState, +} + /// A type of a [`GamepadAxis`]. /// /// ## Usage @@ -1159,20 +1174,35 @@ pub fn gamepad_axis_event_system( /// Uses [`GamepadButtonChangedEvent`]s to update the relevant [`Input`] and [`Axis`] values. pub fn gamepad_button_event_system( - mut button_events: EventReader, + mut button_changed_events: EventReader, mut button_input: ResMut>, + mut button_input_events: EventWriter, settings: Res, ) { - for button_event in button_events.iter() { + for button_event in button_changed_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); if button_property.is_released(value) { - // We don't have to check if the button was previously pressed + // Check if button was previously pressed + if button_input.pressed(button) { + button_input_events.send(GamepadButtonInput { + button, + state: ButtonState::Released, + }); + } + // We don't have to check if the button was previously pressed here // because that check is performed within Input::release() button_input.release(button); } else if button_property.is_pressed(value) { + // Check if button was previously not pressed + if !button_input.pressed(button) { + button_input_events.send(GamepadButtonInput { + button, + state: ButtonState::Pressed, + }); + } button_input.press(button); }; } diff --git a/crates/bevy_input/src/lib.rs b/crates/bevy_input/src/lib.rs index f3f4ab7afc82d..07a9e384e09ac 100644 --- a/crates/bevy_input/src/lib.rs +++ b/crates/bevy_input/src/lib.rs @@ -41,7 +41,7 @@ use gamepad::{ 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, GamepadEvent, + GamepadButtonInput, GamepadButtonType, GamepadConnection, GamepadConnectionEvent, GamepadEvent, GamepadRumbleRequest, GamepadSettings, Gamepads, }; @@ -75,6 +75,7 @@ impl Plugin for InputPlugin { // gamepad .add_event::() .add_event::() + .add_event::() .add_event::() .add_event::() .add_event::() @@ -131,6 +132,7 @@ impl Plugin for InputPlugin { .register_type::() .register_type::() .register_type::() + .register_type::() .register_type::() .register_type::() .register_type::() diff --git a/examples/input/gamepad_input_events.rs b/examples/input/gamepad_input_events.rs index 1e21f7d0f3ad3..cf3971c6a9cc2 100644 --- a/examples/input/gamepad_input_events.rs +++ b/examples/input/gamepad_input_events.rs @@ -2,7 +2,8 @@ use bevy::{ input::gamepad::{ - GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadConnectionEvent, GamepadEvent, + GamepadAxisChangedEvent, GamepadButtonChangedEvent, GamepadButtonInput, + GamepadConnectionEvent, GamepadEvent, }, prelude::*, }; @@ -15,25 +16,37 @@ fn main() { } fn gamepad_events( - mut gamepad_connection_events: EventReader, - mut gamepad_axis_events: EventReader, - mut gamepad_button_events: EventReader, + mut connection_events: EventReader, + mut axis_changed_events: EventReader, + // Handles the continuous measure of how far a button has been pressed down, as measured + // by `Axis`. Whenever that value changes, this event is emitted. + mut button_changed_events: EventReader, + // Handles the boolean measure of whether a button is considered pressed or unpressed, as + // defined by the thresholds in `GamepadSettings::button_settings` and measured by + // `Input`. When the threshold is crossed and the button state changes, + // this event is emmitted. + mut button_input_events: EventReader, ) { - for connection_event in gamepad_connection_events.iter() { + for connection_event in connection_events.iter() { info!("{:?}", connection_event); } - for axis_event in gamepad_axis_events.iter() { + for axis_changed_event in axis_changed_events.iter() { info!( "{:?} of {:?} is changed to {}", - axis_event.axis_type, axis_event.gamepad, axis_event.value + axis_changed_event.axis_type, axis_changed_event.gamepad, axis_changed_event.value ); } - for button_event in gamepad_button_events.iter() { + for button_changed_event in button_changed_events.iter() { info!( "{:?} of {:?} is changed to {}", - button_event.button_type, button_event.gamepad, button_event.value + button_changed_event.button_type, + button_changed_event.gamepad, + button_changed_event.value ); } + for button_input_event in button_input_events.iter() { + info!("{:?}", button_input_event); + } } // If you require in-frame relative event ordering, you can also read the `Gamepad` event