Skip to content
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

Scan all gamepads for inputs if none is registered #168

Merged
merged 12 commits into from
Jul 12, 2022
1 change: 1 addition & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

### Usability

- If no gamepad is registered to a specific `InputMap`, inputs from any gamepad in the `Gamepads` resource will be used.
- Removed the `ActionState::reasons_pressed` API.
- This API was quite complex and not terribly useful.
- This was not needed for axislike inputs in the end.
Expand Down
2 changes: 0 additions & 2 deletions examples/axis_inputs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,6 @@ fn spawn_player(mut commands: Commands) {
SingleGamepadAxis::symmetric(GamepadAxisType::RightStickX, 0.1),
Action::Rudder,
)
// Listen for events on the first gamepad
.set_gamepad(Gamepad(0))
.build(),
});
}
Expand Down
2 changes: 2 additions & 0 deletions examples/multiplayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ impl PlayerBundle {
// This is a quick and hacky solution:
// you should coordinate with the `Gamepads` resource to determine the correct gamepad for each player
// and gracefully handle disconnects
// Note that this step is not required:
// if it is skipped all input maps will read from all connected gamepads
.set_gamepad(Gamepad(0))
.build(),
Player::Two => InputMap::new([
Expand Down
5 changes: 0 additions & 5 deletions examples/single_player.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,6 @@ impl PlayerBundle {
use ArpgAction::*;
let mut input_map = InputMap::default();

// This is a quick and hacky solution:
// you should coordinate with the `Gamepads` resource to determine the correct gamepad for each player
// and gracefully handle disconnects
input_map.set_gamepad(Gamepad(0));

// Movement
input_map.insert(KeyCode::Up, Up);
input_map.insert(GamepadButtonType::DPadUp, Up);
Expand Down
22 changes: 18 additions & 4 deletions src/input_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ use std::marker::PhantomData;
/// Multiple inputs can be mapped to the same action,
/// and each input can be mapped to multiple actions.
///
/// The provided input types must be one of [`GamepadButtonType`], [`KeyCode`] or [`MouseButton`].
/// The provided input types must be able to be converted into a [`UserInput`].
///
/// The maximum number of bindings (total) that can be stored for each action is 16.
/// Insertions will silently fail if you have reached this cap.
///
/// In addition, you can configure the per-mode cap for each [`InputMode`] using [`InputMap::new`] or [`InputMap::set_per_mode_cap`].
/// This can be useful if your UI can only display one or two possible keybindings for each input mode.
///
/// By default, if two actions would be triggered by a combination of buttons,
/// and one combination is a strict subset of the other, only the larger input is registered.
/// For example, pressing both `S` and `Ctrl + S` in your text editor app would save your file,
Expand Down Expand Up @@ -260,12 +257,21 @@ impl<A: Actionlike> InputMap<A> {
// Configuration
impl<A: Actionlike> InputMap<A> {
/// Fetches the [Gamepad] associated with the entity controlled by this entity map
///
/// If this is [`None`], input from any connected gamepad will be used.
#[must_use]
pub fn gamepad(&self) -> Option<Gamepad> {
self.associated_gamepad
}

/// Assigns a particular [`Gamepad`] to the entity controlled by this input map
///
/// If this is not called, input from any connected gamepad will be used.
/// The first matching non-zero input will be accepted,
/// as determined by gamepad registration order.
///
/// Because of this robust fallback behavior,
/// this method can typically be ignored when writing single-player games.
pub fn set_gamepad(&mut self, gamepad: Gamepad) -> &mut Self {
self.associated_gamepad = Some(gamepad);
self
Expand Down Expand Up @@ -580,6 +586,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -597,6 +604,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -612,6 +620,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -628,6 +637,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -642,6 +652,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -658,6 +669,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -676,6 +688,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand All @@ -694,6 +707,7 @@ mod tests {
gamepad_buttons: Some(&gamepad_button_input_stream),
gamepad_button_axes: Some(&gamepad_button_axis_input_stream),
gamepad_axes: Some(&gamepad_axis_input_stream),
gamepads: None,
keyboard: Some(&keyboard_input_stream),
mouse: Some(&mouse_input_stream),
associated_gamepad: Some(Gamepad(42)),
Expand Down
17 changes: 10 additions & 7 deletions src/input_mocking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,7 @@ impl MockInput for World {
Option<ResMut<Input<GamepadButton>>>,
Option<ResMut<Axis<GamepadButton>>>,
Option<ResMut<Axis<GamepadAxis>>>,
Option<ResMut<Gamepads>>,
Option<ResMut<Input<KeyCode>>>,
Option<ResMut<Input<MouseButton>>>,
)> = SystemState::new(self);
Expand All @@ -222,6 +223,7 @@ impl MockInput for World {
mut maybe_gamepad_buttons,
mut maybe_gamepad_button_axes,
mut maybe_gamepad_axes,
mut maybe_gamepads,
mut maybe_keyboard,
mut maybe_mouse,
) = input_system_state.get_mut(self);
Expand All @@ -230,6 +232,7 @@ impl MockInput for World {
gamepad_buttons: maybe_gamepad_buttons.as_deref_mut(),
gamepad_button_axes: maybe_gamepad_button_axes.as_deref_mut(),
gamepad_axes: maybe_gamepad_axes.as_deref_mut(),
gamepads: maybe_gamepads.as_deref_mut(),
keyboard: maybe_keyboard.as_deref_mut(),
mouse: maybe_mouse.as_deref_mut(),
associated_gamepad: gamepad,
Expand All @@ -253,6 +256,7 @@ impl MockInput for World {
Option<ResMut<Input<GamepadButton>>>,
Option<ResMut<Axis<GamepadButton>>>,
Option<ResMut<Axis<GamepadAxis>>>,
Option<ResMut<Gamepads>>,
Option<ResMut<Input<KeyCode>>>,
Option<ResMut<Input<MouseButton>>>,
)> = SystemState::new(self);
Expand All @@ -261,6 +265,7 @@ impl MockInput for World {
mut maybe_gamepad_buttons,
mut maybe_gamepad_button_axes,
mut maybe_gamepad_axes,
mut maybe_gamepads,
mut maybe_keyboard,
mut maybe_mouse,
) = input_system_state.get_mut(self);
Expand All @@ -269,6 +274,7 @@ impl MockInput for World {
gamepad_buttons: maybe_gamepad_buttons.as_deref_mut(),
gamepad_button_axes: maybe_gamepad_button_axes.as_deref_mut(),
gamepad_axes: maybe_gamepad_axes.as_deref_mut(),
gamepads: maybe_gamepads.as_deref_mut(),
keyboard: maybe_keyboard.as_deref_mut(),
mouse: maybe_mouse.as_deref_mut(),
associated_gamepad: gamepad,
Expand All @@ -278,13 +284,7 @@ impl MockInput for World {
}

fn pressed(&mut self, input: impl Into<UserInput>) -> bool {
let gamepad = if let Some(gamepads) = self.get_resource::<Gamepads>() {
gamepads.iter().next().copied()
} else {
None
};

self.pressed_for_gamepad(input, gamepad)
self.pressed_for_gamepad(input, None)
}

fn pressed_for_gamepad(
Expand All @@ -296,6 +296,7 @@ impl MockInput for World {
Option<Res<Input<GamepadButton>>>,
Option<Res<Axis<GamepadButton>>>,
Option<Res<Axis<GamepadAxis>>>,
Option<Res<Gamepads>>,
Option<Res<Input<KeyCode>>>,
Option<Res<Input<MouseButton>>>,
)> = SystemState::new(self);
Expand All @@ -304,6 +305,7 @@ impl MockInput for World {
maybe_gamepad_buttons,
maybe_gamepad_button_axes,
maybe_gamepad_axes,
maybe_gamepads,
maybe_keyboard,
maybe_mouse,
) = input_system_state.get(self);
Expand All @@ -312,6 +314,7 @@ impl MockInput for World {
gamepad_buttons: maybe_gamepad_buttons.as_deref(),
gamepad_button_axes: maybe_gamepad_button_axes.as_deref(),
gamepad_axes: maybe_gamepad_axes.as_deref(),
gamepads: maybe_gamepads.as_deref(),
keyboard: maybe_keyboard.as_deref(),
mouse: maybe_mouse.as_deref(),
associated_gamepad: gamepad,
Expand Down
6 changes: 5 additions & 1 deletion src/systems.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
use bevy_core::Time;
use bevy_ecs::{prelude::*, schedule::ShouldRun};
use bevy_input::{
gamepad::{GamepadAxis, GamepadButton},
gamepad::{GamepadAxis, GamepadButton, Gamepads},
keyboard::KeyCode,
mouse::MouseButton,
Axis, Input,
Expand Down Expand Up @@ -62,6 +62,7 @@ pub fn update_action_state<A: Actionlike>(
maybe_gamepad_button_input_stream: Option<Res<Input<GamepadButton>>>,
maybe_gamepad_button_axes_input_stream: Option<Res<Axis<GamepadButton>>>,
maybe_gamepad_axes_input_stream: Option<Res<Axis<GamepadAxis>>>,
maybe_gamepads: Option<Res<Gamepads>>,
maybe_keyboard_input_stream: Option<Res<Input<KeyCode>>>,
maybe_mouse_input_stream: Option<Res<Input<MouseButton>>>,
clash_strategy: Res<ClashStrategy>,
Expand All @@ -72,6 +73,7 @@ pub fn update_action_state<A: Actionlike>(
let gamepad_buttons = maybe_gamepad_button_input_stream.as_deref();
let gamepad_button_axes = maybe_gamepad_button_axes_input_stream.as_deref();
let gamepad_axes = maybe_gamepad_axes_input_stream.as_deref();
let gamepads = maybe_gamepads.as_deref();

let keyboard = maybe_keyboard_input_stream.as_deref();

Expand All @@ -82,6 +84,7 @@ pub fn update_action_state<A: Actionlike>(
gamepad_buttons,
gamepad_button_axes,
gamepad_axes,
gamepads,
keyboard,
mouse,
associated_gamepad: input_map.gamepad(),
Expand All @@ -95,6 +98,7 @@ pub fn update_action_state<A: Actionlike>(
gamepad_buttons,
gamepad_button_axes,
gamepad_axes,
gamepads,
keyboard,
mouse,
associated_gamepad: input_map.gamepad(),
Expand Down
Loading