Add Gamepads resource (#3257)

# Objective

Fixes #3245 

## Solution

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


Co-authored-by: CrazyRoka <rokarostuk@gmail.com>
Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
Rostyslav Toch 2021-12-08 20:28:08 +00:00
parent ca80fe65ed
commit 01e2141ce3
3 changed files with 65 additions and 37 deletions

View file

@ -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 {
@ -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>>,

View file

@ -15,7 +15,7 @@ pub mod prelude {
pub use crate::{
gamepad::{
Gamepad, GamepadAxis, GamepadAxisType, GamepadButton, GamepadButtonType, GamepadEvent,
GamepadEventType,
GamepadEventType, Gamepads,
},
keyboard::KeyCode,
mouse::MouseButton,
@ -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
@ -64,6 +65,7 @@ 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>>()
@ -71,6 +73,10 @@ impl Plugin for InputPlugin {
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>()

View file

@ -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)) {