diff --git a/src/gamepad.rs b/src/gamepad.rs new file mode 100644 index 0000000..6f1b7c6 --- /dev/null +++ b/src/gamepad.rs @@ -0,0 +1,43 @@ +use bevy::{ + input::gamepad::{GamepadConnection, GamepadEvent}, + prelude::*, +}; + +pub struct GamepadPlugin; + +impl Plugin for GamepadPlugin { + fn build(&self, app: &mut App) { + app.add_systems(Startup, setup); + } +} + +#[derive(Debug, Resource)] +pub struct GamepadOne(pub Gamepad); + +fn setup( + mut commands: Commands, + gamepad1: Option>, + mut gamepad_events: EventReader, +) { + for event in gamepad_events.read() { + let GamepadEvent::Connection(conn) = event + else { + continue; + }; + + match &conn.connection { + GamepadConnection::Connected(info) => { + if gamepad1.is_none() { + commands.insert_resource(GamepadOne(conn.gamepad)); + } + } + GamepadConnection::Disconnected => { + if let Some(GamepadOne(id)) = gamepad1.as_deref() { + if *id == conn.gamepad { + commands.remove_resource::(); + } + } + } + } + } +} diff --git a/src/hud.rs b/src/hud.rs index 147f17f..4fb3b5b 100644 --- a/src/hud.rs +++ b/src/hud.rs @@ -2,10 +2,13 @@ use std::path::Path; use bevy::{ asset::{io::AssetSourceId, AssetPath}, + ecs::query::QueryIter, prelude::*, }; -use crate::{player::Player, score::Score, GameStartEvent, GameState, START_POSITION}; +use crate::{ + gamepad::GamepadOne, player::Player, score::Score, GameStartEvent, GameState, START_POSITION, +}; pub struct HUDPlugin; @@ -149,32 +152,75 @@ pub struct StartButton; pub struct StartMenuUI; fn start_button_logic( + current_state: Res>, mut state: ResMut>, mut score: ResMut, + gamepads: Res>, + gamepad1: Option>, mut button: Query<(&Interaction, &mut BorderColor), With>, mut player_query: Query<(&mut Transform, &mut Visibility), With>, mut ui_elems_query: Query<&mut Visibility, (With, Without)>, mut score_text_query: Query<&mut Text, With>, ) { + if current_state.get() == &GameState::Playing { + return; + }; + + let mut score_text = score_text_query.single_mut(); + let (mut player_transform, mut player_visibility) = player_query.single_mut(); + + if let Some(gamepad) = gamepad1.as_deref() { + let start_btn = GamepadButton { + gamepad: gamepad.0, + button_type: GamepadButtonType::Start, + }; + + if gamepads.pressed(start_btn) { + start_game( + &mut score_text, + &mut score, + &mut state, + &mut ui_elems_query, + &mut player_visibility, + &mut player_transform, + ); + } + } + let (interaction, mut border_color) = button.single_mut(); match *interaction { Interaction::Pressed => { - let mut score_text = score_text_query.single_mut(); - score.0 = 0; - score_text.sections[0].value = format!("{}", score.0); - - state.set(GameState::Playing); - - let (mut player_transform, mut player_visibility) = player_query.single_mut(); - - for mut elem in &mut ui_elems_query { - *elem = Visibility::Hidden; - } - - *player_visibility = Visibility::Visible; - player_transform.translation = START_POSITION; + start_game( + &mut score_text, + &mut score, + &mut state, + &mut ui_elems_query, + &mut player_visibility, + &mut player_transform, + ); } Interaction::Hovered => border_color.0 = Color::WHITE, Interaction::None => border_color.0 = Color::BLACK, } } + +fn start_game( + score_text: &mut Text, + score: &mut Score, + state: &mut NextState, + ui_elems: &mut Query<&mut Visibility, (With, Without)>, + player_visibility: &mut Visibility, + player_transform: &mut Transform, +) { + score.0 = 0; + score_text.sections[0].value = format!("{}", score.0); + + state.set(GameState::Playing); + + for mut elem in ui_elems { + *elem = Visibility::Hidden; + } + + *player_visibility = Visibility::Visible; + player_transform.translation = START_POSITION; +} diff --git a/src/main.rs b/src/main.rs index d98be42..23daed7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,7 @@ use bevy::{ window::{WindowMode, WindowResolution}, }; use common::mouse::{Mouse, MousePlugin}; +use gamepad::GamepadPlugin; use hud::HUDPlugin; use level::LevelPlugin; use player::PlayerPlugin; @@ -15,6 +16,7 @@ use score::ScorePlugin; mod common; mod enemy; +mod gamepad; mod hud; mod level; mod player; @@ -89,6 +91,7 @@ fn main() { // EmbeddedAssetPlugin, LevelPlugin, MousePlugin, + GamepadPlugin, )) .init_state::() .add_event::() diff --git a/src/player.rs b/src/player.rs index eccc1fe..dbd36d7 100644 --- a/src/player.rs +++ b/src/player.rs @@ -1,12 +1,17 @@ use std::f32::consts::PI; -use bevy::{prelude::*, render::view::VisibilityPlugin}; +use bevy::{ + input::gamepad::{GamepadConnection, GamepadEvent}, + prelude::*, + render::view::VisibilityPlugin, +}; use crate::{ common::{ animation::{AnimationBundle, AnimationIndices, AnimationPlugin, AnimationTimer}, velocity::Velocity, }, + gamepad::GamepadOne, level::{Collider, UnitBundle}, GameState, SCREEN_HEIGHT, SCREEN_WIDTH, START_POSITION, }; @@ -66,11 +71,19 @@ fn setup( fn move_player( keys: Res>, + axes: Res>, + gamepads: Res>, + gamepad1: Option>, mut query: Query<(&mut Transform, &mut Velocity), With>, window: Query<&Window>, ) { let (mut transform, mut velocity) = query.single_mut(); velocity.0 = Vec2::ZERO; + + if let Some(gamepad) = gamepad1.as_deref() { + handle_gamepad_movement(&axes, gamepad, &gamepads, &mut velocity); + }; + if keys.pressed(KeyCode::ArrowRight) { velocity.x += 1.0; } @@ -95,3 +108,60 @@ fn move_player( let screen_size: Vec3 = window.physical_size().as_vec2().extend(1.0); transform.translation = transform.translation.clamp(Vec3::ZERO, screen_size); } + +fn handle_gamepad_movement( + axes: &Axis, + gamepad: &GamepadOne, + gamepads: &Res>, + velocity: &mut Velocity, +) { + let axis_lx = GamepadAxis { + gamepad: gamepad.0, + axis_type: GamepadAxisType::LeftStickX, + }; + let axis_ly = GamepadAxis { + gamepad: gamepad.0, + axis_type: GamepadAxisType::LeftStickY, + }; + + if let (Some(x), Some(y)) = (axes.get(axis_lx), axes.get(axis_ly)) { + let left_stick = Vec2::new(x, y); + if left_stick.length() > 0.25 { + *velocity = Velocity(left_stick); + return; + } + } + + let up_btn = GamepadButton { + gamepad: gamepad.0, + button_type: GamepadButtonType::DPadUp, + }; + + let down_btn = GamepadButton { + gamepad: gamepad.0, + button_type: GamepadButtonType::DPadDown, + }; + + let left_btn = GamepadButton { + gamepad: gamepad.0, + button_type: GamepadButtonType::DPadLeft, + }; + + let right_btn = GamepadButton { + gamepad: gamepad.0, + button_type: GamepadButtonType::DPadRight, + }; + + if gamepads.pressed(right_btn) { + velocity.x += 1.0; + } + if gamepads.pressed(left_btn) { + velocity.x -= 1.0; + } + if gamepads.pressed(up_btn) { + velocity.y += 1.0; + } + if gamepads.pressed(down_btn) { + velocity.y -= 1.0; + } +}