From fe3ed310032e48a53c69efe0c7ee1193908482b6 Mon Sep 17 00:00:00 2001 From: Tomato <67799071+100-TomatoJuice@users.noreply.github.com> Date: Sat, 16 Sep 2023 18:07:43 -0700 Subject: [PATCH] Add gamepad registration example (#387) * Create example * Add `set_gamepad()` doc * Update RELEASES.md * invert condition and change to `pressed()` --- RELEASES.md | 1 + examples/register_gamepads.rs | 93 +++++++++++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 examples/register_gamepads.rs diff --git a/RELEASES.md b/RELEASES.md index fc431d6e..0c47fbb4 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -11,6 +11,7 @@ - Fixed invalid example code in README - Added example for setting default controls +- Added example for registering gamepads in a local multiplayer fashion ### Enhancements - Added `DeadZoneShape` for `DualAxis` which allows for different deadzones shapes: cross, rectangle, and ellipse. diff --git a/examples/register_gamepads.rs b/examples/register_gamepads.rs new file mode 100644 index 00000000..d9dfccd9 --- /dev/null +++ b/examples/register_gamepads.rs @@ -0,0 +1,93 @@ +//! Demonstrates how to register gamepads in local multiplayer fashion + +use bevy::{prelude::*, utils::HashMap}; +use leafwing_input_manager::prelude::*; + +fn main() { + App::new() + .add_plugins(DefaultPlugins) + .add_plugins(InputManagerPlugin::::default()) + .init_resource::() + .add_systems(Update, (join, jump, disconnect)) + .run() +} + +#[derive(Actionlike, PartialEq, Eq, Clone, Copy, Hash, Debug, Reflect)] +enum Action { + Jump, + Disconnect, +} + +// This is used to check if a player already exists and which entity to disconnect +#[derive(Resource, Default)] +struct JoinedPlayers(pub HashMap); + +#[derive(Component)] +struct Player { + // This gamepad is used to index each player + gamepad: Gamepad, +} + +fn join( + mut commands: Commands, + mut joined_players: ResMut, + gamepads: Res, + button_inputs: Res>, +) { + for gamepad in gamepads.iter() { + // Join the game when both bumpers (L+R) on the controller are pressed + // We drop down the Bevy's input to get the input from each gamepad + if button_inputs.pressed(GamepadButton::new(gamepad, GamepadButtonType::LeftTrigger)) + && button_inputs.pressed(GamepadButton::new(gamepad, GamepadButtonType::RightTrigger)) + { + // Make sure a player can not join twice + if !joined_players.0.contains_key(&gamepad) { + println!("Player {} has joined the game!", gamepad.id); + + let player = commands + .spawn(InputManagerBundle:: { + action_state: ActionState::default(), + input_map: InputMap::default() + .insert(GamepadButtonType::South, Action::Jump) + .insert(GamepadButtonType::Select, Action::Disconnect) + // Make sure to set the gamepad or all gamepads will be used! + .set_gamepad(gamepad) + .build(), + }) + .insert(Player { gamepad }) + .id(); + + // Insert the created player and its gamepad to the hashmap of joined players + // Since uniqueness was already checked above, we can insert here unchecked + joined_players.0.insert_unique_unchecked(gamepad, player); + } + } + } +} + +fn jump(action_query: Query<(&ActionState, &Player)>) { + // Iterate through each player to see if they jumped + for (action_state, player) in action_query.iter() { + if action_state.just_pressed(Action::Jump) { + println!("Player {} jumped!", player.gamepad.id); + } + } +} + +fn disconnect( + mut commands: Commands, + action_query: Query<(&ActionState, &Player)>, + mut joined_players: ResMut, +) { + for (action_state, player) in action_query.iter() { + if action_state.pressed(Action::Disconnect) { + let player_entity = *joined_players.0.get(&player.gamepad).unwrap(); + + // Despawn the disconnected player and remove them from the joined player list + commands.entity(player_entity).despawn(); + joined_players.0.remove(&player.gamepad); + + println!("Player {} has disconnected!", player.gamepad.id); + } + } +}