Skip to content

Commit

Permalink
Add Gamepads resource (#3257)
Browse files Browse the repository at this point in the history
# Objective

Fixes #3245 

## Solution

- Move GamepadLobby to lib
- Add connection_system to InputPlugin
- Updated gamepad_input example


Co-authored-by: CrazyRoka <[email protected]>
Co-authored-by: Carter Anderson <[email protected]>
  • Loading branch information
3 people committed Dec 8, 2021
1 parent ca80fe6 commit b896294
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 37 deletions.
54 changes: 53 additions & 1 deletion crates/bevy_input/src/gamepad.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,42 @@
use crate::{Axis, Input};
use bevy_app::{EventReader, EventWriter};
use bevy_ecs::system::{Res, ResMut};
use bevy_utils::HashMap;
use bevy_utils::{tracing::info, HashMap, HashSet};

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub struct Gamepad(pub usize);

#[derive(Default)]
/// Container of unique connected [Gamepad]s
///
/// [Gamepad]s are registered and deregistered in [gamepad_connection_system]
pub struct Gamepads {
gamepads: HashSet<Gamepad>,
}

impl Gamepads {
/// Returns true if the [Gamepads] contains a [Gamepad].
pub fn contains(&self, gamepad: &Gamepad) -> bool {
self.gamepads.contains(gamepad)
}

/// Iterates over registered [Gamepad]s
pub fn iter(&self) -> impl Iterator {
self.gamepads.iter()
}

/// Registers [Gamepad].
fn register(&mut self, gamepad: Gamepad) {
self.gamepads.insert(gamepad);
}

/// Deregisters [Gamepad.
fn deregister(&mut self, gamepad: &Gamepad) {
self.gamepads.remove(gamepad);
}
}

#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "serialize", derive(serde::Serialize, serde::Deserialize))]
pub enum GamepadEventType {
Expand Down Expand Up @@ -204,6 +234,28 @@ impl ButtonAxisSettings {
}
}

/// Monitors gamepad connection and disconnection events, updating the [GamepadLobby] resource accordingly
///
/// By default, runs during `CoreStage::PreUpdate` when added via [InputPlugin].
pub fn gamepad_connection_system(
mut gamepads: ResMut<Gamepads>,
mut gamepad_event: EventReader<GamepadEvent>,
) {
for event in gamepad_event.iter() {
match &event {
GamepadEvent(gamepad, GamepadEventType::Connected) => {
gamepads.register(*gamepad);
info!("{:?} Connected", gamepad);
}
GamepadEvent(gamepad, GamepadEventType::Disconnected) => {
gamepads.deregister(gamepad);
info!("{:?} Disconnected", gamepad);
}
_ => (),
}
}
}

pub fn gamepad_event_system(
mut button_input: ResMut<Input<GamepadButton>>,
mut axis: ResMut<Axis<GamepadAxis>>,
Expand Down
12 changes: 9 additions & 3 deletions crates/bevy_input/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub mod prelude {
pub use crate::{
gamepad::{
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent,
GamepadEventType,
GamepadEventType, Gamepads,
},
keyboard::KeyCode,
mouse::MouseButton,
Expand All @@ -27,11 +27,12 @@ pub mod prelude {
use bevy_app::prelude::*;
use keyboard::{keyboard_input_system, KeyCode, KeyboardInput};
use mouse::{mouse_button_input_system, MouseButton, MouseButtonInput, MouseMotion, MouseWheel};
use prelude::Gamepads;
use touch::{touch_screen_input_system, TouchInput, Touches};

use gamepad::{
gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent, GamepadEventRaw,
GamepadSettings,
gamepad_connection_system, gamepad_event_system, GamepadAxis, GamepadButton, GamepadEvent,
GamepadEventRaw, GamepadSettings,
};

/// Adds keyboard and mouse input to an App
Expand Down Expand Up @@ -64,13 +65,18 @@ impl Plugin for InputPlugin {
.add_event::<GamepadEvent>()
.add_event::<GamepadEventRaw>()
.init_resource::<GamepadSettings>()
.init_resource::<Gamepads>()
.init_resource::<Input<GamepadButton>>()
.init_resource::<Axis<GamepadAxis>>()
.init_resource::<Axis<GamepadButton>>()
.add_system_to_stage(
CoreStage::PreUpdate,
gamepad_event_system.label(InputSystem),
)
.add_system_to_stage(
CoreStage::PreUpdate,
gamepad_connection_system.label(InputSystem),
)
// touch
.add_event::<TouchInput>()
.init_resource::<Touches>()
Expand Down
36 changes: 3 additions & 33 deletions examples/input/gamepad_input.rs
Original file line number Diff line number Diff line change
@@ -1,49 +1,19 @@
use bevy::{
input::gamepad::{Gamepad, GamepadButton, GamepadEvent, GamepadEventType},
prelude::*,
utils::HashSet,
};
use bevy::{input::gamepad::GamepadButton, prelude::*};

fn main() {
App::new()
.add_plugins(DefaultPlugins)
.init_resource::<GamepadLobby>()
.add_system_to_stage(CoreStage::PreUpdate, connection_system)
.add_system(gamepad_system)
.run();
}

#[derive(Default)]
struct GamepadLobby {
gamepads: HashSet<Gamepad>,
}

fn connection_system(
mut lobby: ResMut<GamepadLobby>,
mut gamepad_event: EventReader<GamepadEvent>,
) {
for event in gamepad_event.iter() {
match &event {
GamepadEvent(gamepad, GamepadEventType::Connected) => {
lobby.gamepads.insert(*gamepad);
info!("{:?} Connected", gamepad);
}
GamepadEvent(gamepad, GamepadEventType::Disconnected) => {
lobby.gamepads.remove(gamepad);
info!("{:?} Disconnected", gamepad);
}
_ => (),
}
}
}

fn gamepad_system(
lobby: Res<GamepadLobby>,
gamepads: Res<Gamepads>,
button_inputs: Res<Input<GamepadButton>>,
button_axes: Res<Axis<GamepadButton>>,
axes: Res<Axis<GamepadAxis>>,
) {
for gamepad in lobby.gamepads.iter().cloned() {
for gamepad in gamepads.iter().cloned() {
if button_inputs.just_pressed(GamepadButton(gamepad, GamepadButtonType::South)) {
info!("{:?} just pressed South", gamepad);
} else if button_inputs.just_released(GamepadButton(gamepad, GamepadButtonType::South)) {
Expand Down

0 comments on commit b896294

Please sign in to comment.