-
-
Notifications
You must be signed in to change notification settings - Fork 3.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement gamepads as entities #12770
Conversation
I agree with the suggestions from Cart, but feel more strongly about them! Let me know when those are cleaned up and I'll approve and merge this. |
Will LWIM have enough time this late into 0.15? If not, we might want to postpone and merge it early into 0.16 so they have plenty of time. |
The release candidate period makes me confident that LWIM will be able to port over :) |
Remove iter() call from gamepads query in examples Co-authored-by: Carter Anderson <[email protected]>
# Conflicts: # crates/bevy_gilrs/src/gilrs_system.rs # crates/bevy_input/src/gamepad.rs
# Objective - Significantly improve the ergonomics of gamepads and allow new features Gamepads are a bit unergonomic to work with, they use resources but unlike other inputs, they are not limited to a single gamepad, to get around this it uses an identifier (Gamepad) to interact with anything causing all sorts of issues. 1. There are too many: Gamepads, GamepadSettings, GamepadInfo, ButtonInput<T>, 2 Axis<T>. 2. ButtonInput/Axis generic methods become really inconvenient to use e.g. any_pressed() 3. GamepadButton/Axis structs are unnecessary boilerplate: ```rust for gamepad in gamepads.iter() { if button_inputs.just_pressed(GamepadButton::new(gamepad, GamepadButtonType::South)) { info!("{:?} just pressed South", gamepad); } else if button_inputs.just_released(GamepadButton::new(gamepad, GamepadButtonType::South)) { info!("{:?} just released South", gamepad); } } ``` 4. Projects often need to create resources to store the selected gamepad and have to manually check if their gamepad is still valid anyways. - Previously attempted by bevyengine#3419 and bevyengine#12674 ## Solution - Implement gamepads as entities. Using entities solves all the problems above and opens new possibilities. 1. Reduce boilerplate and allows iteration ```rust let is_pressed = gamepads_buttons.iter().any(|buttons| buttons.pressed(GamepadButtonType::South)) ``` 2. ButtonInput/Axis generic methods become ergonomic again ```rust gamepad_buttons.any_just_pressed([GamepadButtonType::Start, GamepadButtonType::Select]) ``` 3. Reduces the number of public components significantly (Gamepad, GamepadSettings, GamepadButtons, GamepadAxes) 4. Components are highly convenient. Gamepad optional features could now be expressed naturally (`Option<Rumble> or Option<Gyro>`), allows devs to attach their own components and filter them, so code like this becomes possible: ```rust fn move_player<const T: usize>( player: Query<&Transform, With<Player<T>>>, gamepads_buttons: Query<&GamepadButtons, With<Player<T>>>, ) { if let Ok(gamepad_buttons) = gamepads_buttons.get_single() { if gamepad_buttons.pressed(GamepadButtonType::South) { // move player } } } ``` --- ## Follow-up - [ ] Run conditions? - [ ] Rumble component # Changelog ## Added TODO ## Changed TODO ## Removed TODO ## Migration Guide TODO --------- Co-authored-by: Carter Anderson <[email protected]>
@alice-i-cecile Gosh you are fast. I didn't even get the chance to update the changelog! Anyways here are some relevant issues you might want to take a look related to this PR:
|
# Objective - Significantly improve the ergonomics of gamepads and allow new features Gamepads are a bit unergonomic to work with, they use resources but unlike other inputs, they are not limited to a single gamepad, to get around this it uses an identifier (Gamepad) to interact with anything causing all sorts of issues. 1. There are too many: Gamepads, GamepadSettings, GamepadInfo, ButtonInput<T>, 2 Axis<T>. 2. ButtonInput/Axis generic methods become really inconvenient to use e.g. any_pressed() 3. GamepadButton/Axis structs are unnecessary boilerplate: ```rust for gamepad in gamepads.iter() { if button_inputs.just_pressed(GamepadButton::new(gamepad, GamepadButtonType::South)) { info!("{:?} just pressed South", gamepad); } else if button_inputs.just_released(GamepadButton::new(gamepad, GamepadButtonType::South)) { info!("{:?} just released South", gamepad); } } ``` 4. Projects often need to create resources to store the selected gamepad and have to manually check if their gamepad is still valid anyways. - Previously attempted by bevyengine#3419 and bevyengine#12674 ## Solution - Implement gamepads as entities. Using entities solves all the problems above and opens new possibilities. 1. Reduce boilerplate and allows iteration ```rust let is_pressed = gamepads_buttons.iter().any(|buttons| buttons.pressed(GamepadButtonType::South)) ``` 2. ButtonInput/Axis generic methods become ergonomic again ```rust gamepad_buttons.any_just_pressed([GamepadButtonType::Start, GamepadButtonType::Select]) ``` 3. Reduces the number of public components significantly (Gamepad, GamepadSettings, GamepadButtons, GamepadAxes) 4. Components are highly convenient. Gamepad optional features could now be expressed naturally (`Option<Rumble> or Option<Gyro>`), allows devs to attach their own components and filter them, so code like this becomes possible: ```rust fn move_player<const T: usize>( player: Query<&Transform, With<Player<T>>>, gamepads_buttons: Query<&GamepadButtons, With<Player<T>>>, ) { if let Ok(gamepad_buttons) = gamepads_buttons.get_single() { if gamepad_buttons.pressed(GamepadButtonType::South) { // move player } } } ``` --- ## Follow-up - [ ] Run conditions? - [ ] Rumble component # Changelog ## Added TODO ## Changed TODO ## Removed TODO ## Migration Guide TODO --------- Co-authored-by: Carter Anderson <[email protected]>
Most of the work here was fallout from the gamepads-as-entities change (bevyengine/bevy#12770), as well as the `PartialReflect` changes. This relies on bevyengine/bevy#15685. That PR must be applied to Bevy for this to build. The most recent upstream commit is 4bf647ff3b0ca7c8ca47496db9cfe03702328473.
Most of the work here was fallout from the gamepads-as-entities change (bevyengine/bevy#12770), as well as the `PartialReflect` changes. This relies on bevyengine/bevy#15685. That PR must be applied to Bevy for this to build. The most recent upstream commit is 4bf647ff3b0ca7c8ca47496db9cfe03702328473.
Thank you to everyone involved with the authoring or reviewing of this PR! This work is relatively important and needs release notes! Head over to bevyengine/bevy-website#1700 if you'd like to help out. |
Found a small functionality regression, opened #16221 |
Objective
Gamepads are a bit unergonomic to work with, they use resources but unlike other inputs, they are not limited to a single gamepad, to get around this it uses an identifier (Gamepad) to interact with anything causing all sorts of inconveniences.
Solution
Using entities solves all the problems above and opens new possibilities.
Option<Rumble> or Option<Gyro>
), allows devs to attach their own components and filter them, so code like this becomes possible:Follow-up
Changelog
Gamepads are now entities instead of resources.
Filtering is now done in bevy_input instead of bevy_gilrs.
RawGamepad events are made available to users.
Added
Changed
Removed
Migration Guide
Gamepad input is no longer accessed using resources, instead they are entities and are accessible using the Gamepad component as long as the gamepad is connected.
Gamepads resource has been deleted, instead of using an internal id to identify gamepads you can use its Entity. Disconnected gamepads will NOT be despawned. Gamepad components that don't need to preserve their state will be removed i.e. Gamepad component is removed, but GamepadSettings is kept.
Reconnected gamepads will try to preserve their Entity id and necessary components will be re-inserted.
GamepadSettings is no longer a resource, instead it is a component attached to the Gamepad entity.
Axis, Axis and ButtonInput methods are accessible via Gamepad component.