Gamepad improvements (#16222)

# Objective

Closes #16221.

## Solution

- Make `Gamepad` fields public and remove delegates / getters.
- Move `impl Into` to `Axis` methods (delegates for `Axis` used `impl
Into` to allow passing both `GamepadAxis` and `GamepadButton`).
- Improve docs.

## Testing

- I run tests.

Not sure if the migration guide is needed, since it's a feature from RC,
but I wrote it just in case.

---

## Migration Guide

- `Gamepad` fields are now public.
- Instead of using `Gamepad` delegates like `Gamepad::just_pressed`,
call these methods directly on the fields.

---------

Co-authored-by: Alice Cecile <alice.i.cecile@gmail.com>
This commit is contained in:
Hennadii Chernyshchyk 2024-11-04 20:05:24 +03:00 committed by GitHub
parent 8d24efe60c
commit b0058dc54b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 69 additions and 237 deletions

View file

@ -45,16 +45,16 @@ where
/// If the `input_device`: /// If the `input_device`:
/// - was present before, the position data is updated, and the old value is returned. /// - was present before, the position data is updated, and the old value is returned.
/// - wasn't present before, `None` is returned. /// - wasn't present before, `None` is returned.
pub fn set(&mut self, input_device: T, position_data: f32) -> Option<f32> { pub fn set(&mut self, input_device: impl Into<T>, position_data: f32) -> Option<f32> {
self.axis_data.insert(input_device, position_data) self.axis_data.insert(input_device.into(), position_data)
} }
/// Returns the position data of the provided `input_device`. /// Returns the position data of the provided `input_device`.
/// ///
/// This will be clamped between [`Axis::MIN`] and [`Axis::MAX`] inclusive. /// This will be clamped between [`Axis::MIN`] and [`Axis::MAX`] inclusive.
pub fn get(&self, input_device: T) -> Option<f32> { pub fn get(&self, input_device: impl Into<T>) -> Option<f32> {
self.axis_data self.axis_data
.get(&input_device) .get(&input_device.into())
.copied() .copied()
.map(|value| value.clamp(Self::MIN, Self::MAX)) .map(|value| value.clamp(Self::MIN, Self::MAX))
} }
@ -66,13 +66,13 @@ where
/// Use for things like camera zoom, where you want devices like mouse wheels to be able to /// Use for things like camera zoom, where you want devices like mouse wheels to be able to
/// exceed the normal range. If being able to move faster on one input device /// exceed the normal range. If being able to move faster on one input device
/// than another would give an unfair advantage, you should likely use [`Axis::get`] instead. /// than another would give an unfair advantage, you should likely use [`Axis::get`] instead.
pub fn get_unclamped(&self, input_device: T) -> Option<f32> { pub fn get_unclamped(&self, input_device: impl Into<T>) -> Option<f32> {
self.axis_data.get(&input_device).copied() self.axis_data.get(&input_device.into()).copied()
} }
/// Removes the position data of the `input_device`, returning the position data if the input device was previously set. /// Removes the position data of the `input_device`, returning the position data if the input device was previously set.
pub fn remove(&mut self, input_device: T) -> Option<f32> { pub fn remove(&mut self, input_device: impl Into<T>) -> Option<f32> {
self.axis_data.remove(&input_device) self.axis_data.remove(&input_device.into())
} }
/// Returns an iterator over all axes. /// Returns an iterator over all axes.

View file

@ -306,13 +306,12 @@ pub enum ButtonSettingsError {
}, },
} }
/// The [`Gamepad`] [`component`](Component) stores a connected gamepad's metadata such as the `name` and its [`GamepadButton`] and [`GamepadAxis`]. /// Stores a connected gamepad's state and any metadata such as the device name.
/// ///
/// The [`entity`](Entity) representing a gamepad and its [`minimal components`](GamepadSettings) are automatically managed. /// An entity with this component is spawned automatically after [`GamepadConnectionEvent`]
/// and updated by [`gamepad_event_processing_system`].
/// ///
/// # Usage /// See also [`GamepadSettings`] for configuration.
///
/// The only way to obtain a [`Gamepad`] is by [`query`](Query).
/// ///
/// # Examples /// # Examples
/// ///
@ -321,14 +320,15 @@ pub enum ButtonSettingsError {
/// # use bevy_ecs::system::Query; /// # use bevy_ecs::system::Query;
/// # /// #
/// fn gamepad_usage_system(gamepads: Query<&Gamepad>) { /// fn gamepad_usage_system(gamepads: Query<&Gamepad>) {
/// for gamepad in gamepads.iter() { /// for gamepad in &gamepads {
/// println!("{}", gamepad.name()); /// let name = &gamepad.info.name;
/// println!("{name}");
/// ///
/// if gamepad.just_pressed(GamepadButton::North) { /// if gamepad.digital.just_pressed(GamepadButton::North) {
/// println!("{} just pressed North", gamepad.name()) /// println!("{name} just pressed North")
/// } /// }
/// ///
/// if let Some(left_stick_x) = gamepad.get(GamepadAxis::LeftStickX) { /// if let Some(left_stick_x) = gamepad.analog.get(GamepadAxis::LeftStickX) {
/// println!("left stick X: {}", left_stick_x) /// println!("left stick X: {}", left_stick_x)
/// } /// }
/// } /// }
@ -338,22 +338,23 @@ pub enum ButtonSettingsError {
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug))]
#[require(GamepadSettings)] #[require(GamepadSettings)]
pub struct Gamepad { pub struct Gamepad {
info: GamepadInfo, /// Metadata.
pub info: GamepadInfo,
/// [`ButtonInput`] of [`GamepadButton`] representing their digital state /// [`ButtonInput`] of [`GamepadButton`] representing their digital state
pub(crate) digital: ButtonInput<GamepadButton>, pub digital: ButtonInput<GamepadButton>,
/// [`Axis`] of [`GamepadButton`] representing their analog state. /// [`Axis`] of [`GamepadButton`] representing their analog state.
pub(crate) analog: Axis<GamepadInput>, pub analog: Axis<GamepadInput>,
} }
impl Gamepad { impl Gamepad {
/// Creates a gamepad with the given metadata. /// Creates a gamepad with the given metadata.
fn new(info: GamepadInfo) -> Self { pub fn new(info: GamepadInfo) -> Self {
let mut analog = Axis::default(); let mut analog = Axis::default();
for button in GamepadButton::all().iter().copied() { for button in GamepadButton::all().iter().copied() {
analog.set(button.into(), 0.0); analog.set(button, 0.0);
} }
for axis_type in GamepadAxis::all().iter().copied() { for axis_type in GamepadAxis::all().iter().copied() {
analog.set(axis_type.into(), 0.0); analog.set(axis_type, 0.0);
} }
Self { Self {
info, info,
@ -362,168 +363,38 @@ impl Gamepad {
} }
} }
/// The name of the gamepad.
///
/// This name is generally defined by the OS.
///
/// For example on Windows the name may be "HID-compliant game controller".
pub fn name(&self) -> &str {
self.info.name.as_str()
}
/// Returns the USB vendor ID as assigned by the USB-IF, if available.
pub fn vendor_id(&self) -> Option<u16> {
self.info.vendor_id
}
/// Returns the USB product ID as assigned by the [vendor], if available.
///
/// [vendor]: Self::vendor_id
pub fn product_id(&self) -> Option<u16> {
self.info.product_id
}
/// Returns the analog data of the provided [`GamepadAxis`] or [`GamepadButton`].
///
/// This will be clamped between [[`Axis::MIN`],[`Axis::MAX`]].
pub fn get(&self, input: impl Into<GamepadInput>) -> Option<f32> {
self.analog.get(input.into())
}
/// Returns the unclamped analog data of the provided [`GamepadAxis`] or [`GamepadButton`].
///
/// This value may be outside the [`Axis::MIN`] and [`Axis::MAX`] range.
pub fn get_unclamped(&self, input: impl Into<GamepadInput>) -> Option<f32> {
self.analog.get_unclamped(input.into())
}
/// Returns the left stick as a [`Vec2`] /// Returns the left stick as a [`Vec2`]
pub fn left_stick(&self) -> Vec2 { pub fn left_stick(&self) -> Vec2 {
Vec2 { Vec2 {
x: self.get(GamepadAxis::LeftStickX).unwrap_or(0.0), x: self.analog.get(GamepadAxis::LeftStickX).unwrap_or(0.0),
y: self.get(GamepadAxis::LeftStickY).unwrap_or(0.0), y: self.analog.get(GamepadAxis::LeftStickY).unwrap_or(0.0),
} }
} }
/// Returns the right stick as a [`Vec2`] /// Returns the right stick as a [`Vec2`]
pub fn right_stick(&self) -> Vec2 { pub fn right_stick(&self) -> Vec2 {
Vec2 { Vec2 {
x: self.get(GamepadAxis::RightStickX).unwrap_or(0.0), x: self.analog.get(GamepadAxis::RightStickX).unwrap_or(0.0),
y: self.get(GamepadAxis::RightStickY).unwrap_or(0.0), y: self.analog.get(GamepadAxis::RightStickY).unwrap_or(0.0),
} }
} }
/// Returns the directional pad as a [`Vec2`] /// Returns the directional pad as a [`Vec2`]
pub fn dpad(&self) -> Vec2 { pub fn dpad(&self) -> Vec2 {
Vec2 { Vec2 {
x: self.get(GamepadButton::DPadRight).unwrap_or(0.0) x: self.analog.get(GamepadButton::DPadRight).unwrap_or(0.0)
- self.get(GamepadButton::DPadLeft).unwrap_or(0.0), - self.analog.get(GamepadButton::DPadLeft).unwrap_or(0.0),
y: self.get(GamepadButton::DPadUp).unwrap_or(0.0) y: self.analog.get(GamepadButton::DPadUp).unwrap_or(0.0)
- self.get(GamepadButton::DPadDown).unwrap_or(0.0), - self.analog.get(GamepadButton::DPadDown).unwrap_or(0.0),
} }
} }
/// Returns `true` if the [`GamepadButton`] has been pressed.
pub fn pressed(&self, button_type: GamepadButton) -> bool {
self.digital.pressed(button_type)
}
/// Returns `true` if any item in [`GamepadButton`] has been pressed.
pub fn any_pressed(&self, button_inputs: impl IntoIterator<Item = GamepadButton>) -> bool {
button_inputs
.into_iter()
.any(|button_type| self.pressed(button_type))
}
/// Returns `true` if all items in [`GamepadButton`] have been pressed.
pub fn all_pressed(&self, button_inputs: impl IntoIterator<Item = GamepadButton>) -> bool {
button_inputs
.into_iter()
.all(|button_type| self.pressed(button_type))
}
/// Returns `true` if the [`GamepadButton`] has been pressed during the current frame.
///
/// Note: This function does not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_released`].
pub fn just_pressed(&self, button_type: GamepadButton) -> bool {
self.digital.just_pressed(button_type)
}
/// Returns `true` if any item in [`GamepadButton`] has been pressed during the current frame.
pub fn any_just_pressed(&self, button_inputs: impl IntoIterator<Item = GamepadButton>) -> bool {
button_inputs
.into_iter()
.any(|button_type| self.just_pressed(button_type))
}
/// Returns `true` if all items in [`GamepadButton`] have been just pressed.
pub fn all_just_pressed(&self, button_inputs: impl IntoIterator<Item = GamepadButton>) -> bool {
button_inputs
.into_iter()
.all(|button_type| self.just_pressed(button_type))
}
/// Returns `true` if the [`GamepadButton`] has been released during the current frame.
///
/// Note: This function does not imply information regarding the current state of [`ButtonInput::pressed`] or [`ButtonInput::just_pressed`].
pub fn just_released(&self, button_type: GamepadButton) -> bool {
self.digital.just_released(button_type)
}
/// Returns `true` if any item in [`GamepadButton`] has just been released.
pub fn any_just_released(
&self,
button_inputs: impl IntoIterator<Item = GamepadButton>,
) -> bool {
button_inputs
.into_iter()
.any(|button_type| self.just_released(button_type))
}
/// Returns `true` if all items in [`GamepadButton`] have just been released.
pub fn all_just_released(
&self,
button_inputs: impl IntoIterator<Item = GamepadButton>,
) -> bool {
button_inputs
.into_iter()
.all(|button_type| self.just_released(button_type))
}
/// Returns an iterator over all digital [button]s that are pressed.
///
/// [button]: GamepadButton
pub fn get_pressed(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_pressed()
}
/// Returns an iterator over all digital [button]s that were just pressed.
///
/// [button]: GamepadButton
pub fn get_just_pressed(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_just_pressed()
}
/// Returns an iterator over all digital [button]s that were just released.
///
/// [button]: GamepadButton
pub fn get_just_released(&self) -> impl Iterator<Item = &GamepadButton> {
self.digital.get_just_released()
}
/// Returns an iterator over all analog [axes].
///
/// [axes]: GamepadInput
pub fn get_analog_axes(&self) -> impl Iterator<Item = &GamepadInput> {
self.analog.all_axes()
}
} }
// Note that we don't expose `gilrs::Gamepad::uuid` due to // Note that we don't expose `gilrs::Gamepad::uuid` due to
// https://gitlab.com/gilrs-project/gilrs/-/issues/153. // https://gitlab.com/gilrs-project/gilrs/-/issues/153.
// //
/// Metadata associated with a [`Gamepad`]. /// Metadata associated with a [`Gamepad`].
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Default, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))] #[cfg_attr(feature = "bevy_reflect", derive(Reflect), reflect(Debug, PartialEq))]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr( #[cfg_attr(
@ -1426,12 +1297,12 @@ pub fn gamepad_event_processing_system(
}; };
let Some(filtered_value) = gamepad_settings let Some(filtered_value) = gamepad_settings
.get_axis_settings(axis) .get_axis_settings(axis)
.filter(value, gamepad_axis.get(axis)) .filter(value, gamepad_axis.analog.get(axis))
else { else {
continue; continue;
}; };
gamepad_axis.analog.set(axis.into(), filtered_value); gamepad_axis.analog.set(axis, filtered_value);
let send_event = GamepadAxisChangedEvent::new(gamepad, axis, filtered_value); let send_event = GamepadAxisChangedEvent::new(gamepad, axis, filtered_value);
processed_axis_events.send(send_event); processed_axis_events.send(send_event);
processed_events.send(GamepadEvent::from(send_event)); processed_events.send(GamepadEvent::from(send_event));
@ -1447,16 +1318,16 @@ pub fn gamepad_event_processing_system(
}; };
let Some(filtered_value) = settings let Some(filtered_value) = settings
.get_button_axis_settings(button) .get_button_axis_settings(button)
.filter(value, gamepad_buttons.get(button)) .filter(value, gamepad_buttons.analog.get(button))
else { else {
continue; continue;
}; };
let button_settings = settings.get_button_settings(button); let button_settings = settings.get_button_settings(button);
gamepad_buttons.analog.set(button.into(), filtered_value); gamepad_buttons.analog.set(button, filtered_value);
if button_settings.is_released(filtered_value) { if button_settings.is_released(filtered_value) {
// Check if button was previously pressed // Check if button was previously pressed
if gamepad_buttons.pressed(button) { if gamepad_buttons.digital.pressed(button) {
processed_digital_events.send(GamepadButtonStateChangedEvent::new( processed_digital_events.send(GamepadButtonStateChangedEvent::new(
gamepad, gamepad,
button, button,
@ -1468,7 +1339,7 @@ pub fn gamepad_event_processing_system(
gamepad_buttons.digital.release(button); gamepad_buttons.digital.release(button);
} else if button_settings.is_pressed(filtered_value) { } else if button_settings.is_pressed(filtered_value) {
// Check if button was previously not pressed // Check if button was previously not pressed
if !gamepad_buttons.pressed(button) { if !gamepad_buttons.digital.pressed(button) {
processed_digital_events.send(GamepadButtonStateChangedEvent::new( processed_digital_events.send(GamepadButtonStateChangedEvent::new(
gamepad, gamepad,
button, button,
@ -2000,11 +1871,7 @@ mod tests {
.resource_mut::<Events<GamepadConnectionEvent>>() .resource_mut::<Events<GamepadConnectionEvent>>()
.send(GamepadConnectionEvent::new( .send(GamepadConnectionEvent::new(
gamepad, gamepad,
Connected(GamepadInfo { Connected(GamepadInfo::default()),
name: String::from("Gamepad test"),
vendor_id: None,
product_id: None,
}),
)); ));
gamepad gamepad
} }
@ -2522,13 +2389,8 @@ mod tests {
assert_eq!(event.button, GamepadButton::DPadDown); assert_eq!(event.button, GamepadButton::DPadDown);
assert_eq!(event.state, ButtonState::Pressed); assert_eq!(event.state, ButtonState::Pressed);
} }
assert!(ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(gamepad.digital.pressed(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.pressed(GamepadButton::DPadDown));
ctx.app ctx.app
.world_mut() .world_mut()
@ -2543,13 +2405,8 @@ mod tests {
.len(), .len(),
0 0
); );
assert!(ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(gamepad.digital.pressed(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.pressed(GamepadButton::DPadDown));
} }
#[test] #[test]
@ -2568,23 +2425,13 @@ mod tests {
ctx.update(); ctx.update();
// Check it is flagged for this frame // Check it is flagged for this frame
assert!(ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(gamepad.digital.just_pressed(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.just_pressed(GamepadButton::DPadDown));
ctx.update(); ctx.update();
//Check it clears next frame //Check it clears next frame
assert!(!ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(!gamepad.digital.just_pressed(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.just_pressed(GamepadButton::DPadDown));
} }
#[test] #[test]
fn gamepad_buttons_released() { fn gamepad_buttons_released() {
@ -2627,13 +2474,8 @@ mod tests {
assert_eq!(event.button, GamepadButton::DPadDown); assert_eq!(event.button, GamepadButton::DPadDown);
assert_eq!(event.state, ButtonState::Released); assert_eq!(event.state, ButtonState::Released);
} }
assert!(!ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(!gamepad.digital.pressed(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.pressed(GamepadButton::DPadDown));
ctx.app ctx.app
.world_mut() .world_mut()
.resource_mut::<Events<GamepadButtonStateChangedEvent>>() .resource_mut::<Events<GamepadButtonStateChangedEvent>>()
@ -2672,23 +2514,13 @@ mod tests {
ctx.update(); ctx.update();
// Check it is flagged for this frame // Check it is flagged for this frame
assert!(ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(gamepad.digital.just_released(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.just_released(GamepadButton::DPadDown));
ctx.update(); ctx.update();
//Check it clears next frame // Check it clears next frame
assert!(!ctx let gamepad = ctx.app.world_mut().get::<Gamepad>(entity).unwrap();
.app assert!(!gamepad.digital.just_released(GamepadButton::DPadDown));
.world_mut()
.query::<&Gamepad>()
.get(ctx.app.world(), entity)
.unwrap()
.just_released(GamepadButton::DPadDown));
} }
#[test] #[test]

View file

@ -11,18 +11,18 @@ fn main() {
fn gamepad_system(gamepads: Query<(Entity, &Gamepad)>) { fn gamepad_system(gamepads: Query<(Entity, &Gamepad)>) {
for (entity, gamepad) in &gamepads { for (entity, gamepad) in &gamepads {
if gamepad.just_pressed(GamepadButton::South) { if gamepad.digital.just_pressed(GamepadButton::South) {
info!("{:?} just pressed South", entity); info!("{:?} just pressed South", entity);
} else if gamepad.just_released(GamepadButton::South) { } else if gamepad.digital.just_released(GamepadButton::South) {
info!("{:?} just released South", entity); info!("{:?} just released South", entity);
} }
let right_trigger = gamepad.get(GamepadButton::RightTrigger2).unwrap(); let right_trigger = gamepad.analog.get(GamepadButton::RightTrigger2).unwrap();
if right_trigger.abs() > 0.01 { if right_trigger.abs() > 0.01 {
info!("{:?} RightTrigger2 value is {}", entity, right_trigger); info!("{:?} RightTrigger2 value is {}", entity, right_trigger);
} }
let left_stick_x = gamepad.get(GamepadAxis::LeftStickX).unwrap(); let left_stick_x = gamepad.analog.get(GamepadAxis::LeftStickX).unwrap();
if left_stick_x.abs() > 0.01 { if left_stick_x.abs() > 0.01 {
info!("{:?} LeftStickX value is {}", entity, left_stick_x); info!("{:?} LeftStickX value is {}", entity, left_stick_x);
} }

View file

@ -19,7 +19,7 @@ fn gamepad_system(
mut rumble_requests: EventWriter<GamepadRumbleRequest>, mut rumble_requests: EventWriter<GamepadRumbleRequest>,
) { ) {
for (entity, gamepad) in &gamepads { for (entity, gamepad) in &gamepads {
if gamepad.just_pressed(GamepadButton::North) { if gamepad.digital.just_pressed(GamepadButton::North) {
info!( info!(
"North face button: strong (low-frequency) with low intensity for rumble for 5 seconds. Press multiple times to increase intensity." "North face button: strong (low-frequency) with low intensity for rumble for 5 seconds. Press multiple times to increase intensity."
); );
@ -30,7 +30,7 @@ fn gamepad_system(
}); });
} }
if gamepad.just_pressed(GamepadButton::East) { if gamepad.digital.just_pressed(GamepadButton::East) {
info!("East face button: maximum rumble on both motors for 5 seconds"); info!("East face button: maximum rumble on both motors for 5 seconds");
rumble_requests.send(GamepadRumbleRequest::Add { rumble_requests.send(GamepadRumbleRequest::Add {
gamepad: entity, gamepad: entity,
@ -39,7 +39,7 @@ fn gamepad_system(
}); });
} }
if gamepad.just_pressed(GamepadButton::South) { if gamepad.digital.just_pressed(GamepadButton::South) {
info!("South face button: low-intensity rumble on the weak motor for 0.5 seconds"); info!("South face button: low-intensity rumble on the weak motor for 0.5 seconds");
rumble_requests.send(GamepadRumbleRequest::Add { rumble_requests.send(GamepadRumbleRequest::Add {
gamepad: entity, gamepad: entity,
@ -48,7 +48,7 @@ fn gamepad_system(
}); });
} }
if gamepad.just_pressed(GamepadButton::West) { if gamepad.digital.just_pressed(GamepadButton::West) {
info!("West face button: custom rumble intensity for 5 second"); info!("West face button: custom rumble intensity for 5 second");
rumble_requests.send(GamepadRumbleRequest::Add { rumble_requests.send(GamepadRumbleRequest::Add {
gamepad: entity, gamepad: entity,
@ -62,7 +62,7 @@ fn gamepad_system(
}); });
} }
if gamepad.just_pressed(GamepadButton::Start) { if gamepad.digital.just_pressed(GamepadButton::Start) {
info!("Start button: Interrupt the current rumble"); info!("Start button: Interrupt the current rumble");
rumble_requests.send(GamepadRumbleRequest::Stop { gamepad: entity }); rumble_requests.send(GamepadRumbleRequest::Stop { gamepad: entity });
} }

View file

@ -393,12 +393,12 @@ fn update_buttons(
materials: Res<ButtonMaterials>, materials: Res<ButtonMaterials>,
mut query: Query<(&mut MeshMaterial2d<ColorMaterial>, &ReactTo)>, mut query: Query<(&mut MeshMaterial2d<ColorMaterial>, &ReactTo)>,
) { ) {
for buttons in &gamepads { for gamepad in &gamepads {
for (mut handle, react_to) in query.iter_mut() { for (mut handle, react_to) in query.iter_mut() {
if buttons.just_pressed(**react_to) { if gamepad.digital.just_pressed(**react_to) {
*handle = materials.active.clone(); *handle = materials.active.clone();
} }
if buttons.just_released(**react_to) { if gamepad.digital.just_released(**react_to) {
*handle = materials.normal.clone(); *handle = materials.normal.clone();
} }
} }
@ -458,7 +458,7 @@ fn update_connected(
let formatted = gamepads let formatted = gamepads
.iter() .iter()
.map(|(entity, gamepad)| format!("{} - {}", entity, gamepad.name())) .map(|(entity, gamepad)| format!("{} - {}", entity, gamepad.info.name))
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"); .join("\n");