Add GamepadButtonInput event (#9008)

# Objective

Add `GamepadButtonInput` event
Resolves #8988

## Solution

- Add `GamepadButtonInput` type
- Emit `GamepadButtonInput` events whenever `Input<GamepadButton>` is
written to
- Update example

---------

Co-authored-by: François <mockersf@gmail.com>
This commit is contained in:
Joshua Walton 2023-08-20 21:31:27 +01:00 committed by GitHub
parent a024a1f3b9
commit 140d9612e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 14 deletions

View file

@ -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<GamepadButtonChangedEvent>,
mut button_changed_events: EventReader<GamepadButtonChangedEvent>,
mut button_input: ResMut<Input<GamepadButton>>,
mut button_input_events: EventWriter<GamepadButtonInput>,
settings: Res<GamepadSettings>,
) {
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<T>::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);
};
}

View file

@ -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::<GamepadConnectionEvent>()
.add_event::<GamepadButtonChangedEvent>()
.add_event::<GamepadButtonInput>()
.add_event::<GamepadAxisChangedEvent>()
.add_event::<GamepadEvent>()
.add_event::<GamepadRumbleRequest>()
@ -131,6 +132,7 @@ impl Plugin for InputPlugin {
.register_type::<GamepadConnection>()
.register_type::<GamepadButtonType>()
.register_type::<GamepadButton>()
.register_type::<GamepadButtonInput>()
.register_type::<GamepadAxisType>()
.register_type::<GamepadAxis>()
.register_type::<GamepadSettings>()

View file

@ -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<GamepadConnectionEvent>,
mut gamepad_axis_events: EventReader<GamepadAxisChangedEvent>,
mut gamepad_button_events: EventReader<GamepadButtonChangedEvent>,
mut connection_events: EventReader<GamepadConnectionEvent>,
mut axis_changed_events: EventReader<GamepadAxisChangedEvent>,
// Handles the continuous measure of how far a button has been pressed down, as measured
// by `Axis<GamepadButton>`. Whenever that value changes, this event is emitted.
mut button_changed_events: EventReader<GamepadButtonChangedEvent>,
// 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<GamepadButton>`. When the threshold is crossed and the button state changes,
// this event is emmitted.
mut button_input_events: EventReader<GamepadButtonInput>,
) {
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