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

[Merged by Bors] - Add Gamepads resource #3257

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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<Item = &Gamepad> + '_ {
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 @@ -201,6 +231,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