Added controller support
parent
e942867f8e
commit
b72d550b4d
|
@ -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<Res<GamepadOne>>,
|
||||||
|
mut gamepad_events: EventReader<GamepadEvent>,
|
||||||
|
) {
|
||||||
|
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::<GamepadOne>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
src/hud.rs
64
src/hud.rs
|
@ -2,10 +2,13 @@ use std::path::Path;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{io::AssetSourceId, AssetPath},
|
asset::{io::AssetSourceId, AssetPath},
|
||||||
|
ecs::query::QueryIter,
|
||||||
prelude::*,
|
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;
|
pub struct HUDPlugin;
|
||||||
|
|
||||||
|
@ -149,32 +152,75 @@ pub struct StartButton;
|
||||||
pub struct StartMenuUI;
|
pub struct StartMenuUI;
|
||||||
|
|
||||||
fn start_button_logic(
|
fn start_button_logic(
|
||||||
|
current_state: Res<State<GameState>>,
|
||||||
mut state: ResMut<NextState<GameState>>,
|
mut state: ResMut<NextState<GameState>>,
|
||||||
mut score: ResMut<Score>,
|
mut score: ResMut<Score>,
|
||||||
|
gamepads: Res<ButtonInput<GamepadButton>>,
|
||||||
|
gamepad1: Option<Res<GamepadOne>>,
|
||||||
mut button: Query<(&Interaction, &mut BorderColor), With<StartButton>>,
|
mut button: Query<(&Interaction, &mut BorderColor), With<StartButton>>,
|
||||||
mut player_query: Query<(&mut Transform, &mut Visibility), With<Player>>,
|
mut player_query: Query<(&mut Transform, &mut Visibility), With<Player>>,
|
||||||
mut ui_elems_query: Query<&mut Visibility, (With<StartMenuUI>, Without<Player>)>,
|
mut ui_elems_query: Query<&mut Visibility, (With<StartMenuUI>, Without<Player>)>,
|
||||||
mut score_text_query: Query<&mut Text, With<ScoreText>>,
|
mut score_text_query: Query<&mut Text, With<ScoreText>>,
|
||||||
) {
|
) {
|
||||||
|
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();
|
let (interaction, mut border_color) = button.single_mut();
|
||||||
match *interaction {
|
match *interaction {
|
||||||
Interaction::Pressed => {
|
Interaction::Pressed => {
|
||||||
let mut score_text = score_text_query.single_mut();
|
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<GameState>,
|
||||||
|
ui_elems: &mut Query<&mut Visibility, (With<StartMenuUI>, Without<Player>)>,
|
||||||
|
player_visibility: &mut Visibility,
|
||||||
|
player_transform: &mut Transform,
|
||||||
|
) {
|
||||||
score.0 = 0;
|
score.0 = 0;
|
||||||
score_text.sections[0].value = format!("{}", score.0);
|
score_text.sections[0].value = format!("{}", score.0);
|
||||||
|
|
||||||
state.set(GameState::Playing);
|
state.set(GameState::Playing);
|
||||||
|
|
||||||
let (mut player_transform, mut player_visibility) = player_query.single_mut();
|
for mut elem in ui_elems {
|
||||||
|
|
||||||
for mut elem in &mut ui_elems_query {
|
|
||||||
*elem = Visibility::Hidden;
|
*elem = Visibility::Hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
*player_visibility = Visibility::Visible;
|
*player_visibility = Visibility::Visible;
|
||||||
player_transform.translation = START_POSITION;
|
player_transform.translation = START_POSITION;
|
||||||
}
|
}
|
||||||
Interaction::Hovered => border_color.0 = Color::WHITE,
|
|
||||||
Interaction::None => border_color.0 = Color::BLACK,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ use bevy::{
|
||||||
window::{WindowMode, WindowResolution},
|
window::{WindowMode, WindowResolution},
|
||||||
};
|
};
|
||||||
use common::mouse::{Mouse, MousePlugin};
|
use common::mouse::{Mouse, MousePlugin};
|
||||||
|
use gamepad::GamepadPlugin;
|
||||||
use hud::HUDPlugin;
|
use hud::HUDPlugin;
|
||||||
use level::LevelPlugin;
|
use level::LevelPlugin;
|
||||||
use player::PlayerPlugin;
|
use player::PlayerPlugin;
|
||||||
|
@ -15,6 +16,7 @@ use score::ScorePlugin;
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
mod enemy;
|
mod enemy;
|
||||||
|
mod gamepad;
|
||||||
mod hud;
|
mod hud;
|
||||||
mod level;
|
mod level;
|
||||||
mod player;
|
mod player;
|
||||||
|
@ -89,6 +91,7 @@ fn main() {
|
||||||
// EmbeddedAssetPlugin,
|
// EmbeddedAssetPlugin,
|
||||||
LevelPlugin,
|
LevelPlugin,
|
||||||
MousePlugin,
|
MousePlugin,
|
||||||
|
GamepadPlugin,
|
||||||
))
|
))
|
||||||
.init_state::<GameState>()
|
.init_state::<GameState>()
|
||||||
.add_event::<GameOverEvent>()
|
.add_event::<GameOverEvent>()
|
||||||
|
|
|
@ -1,12 +1,17 @@
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
use bevy::{prelude::*, render::view::VisibilityPlugin};
|
use bevy::{
|
||||||
|
input::gamepad::{GamepadConnection, GamepadEvent},
|
||||||
|
prelude::*,
|
||||||
|
render::view::VisibilityPlugin,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
common::{
|
common::{
|
||||||
animation::{AnimationBundle, AnimationIndices, AnimationPlugin, AnimationTimer},
|
animation::{AnimationBundle, AnimationIndices, AnimationPlugin, AnimationTimer},
|
||||||
velocity::Velocity,
|
velocity::Velocity,
|
||||||
},
|
},
|
||||||
|
gamepad::GamepadOne,
|
||||||
level::{Collider, UnitBundle},
|
level::{Collider, UnitBundle},
|
||||||
GameState, SCREEN_HEIGHT, SCREEN_WIDTH, START_POSITION,
|
GameState, SCREEN_HEIGHT, SCREEN_WIDTH, START_POSITION,
|
||||||
};
|
};
|
||||||
|
@ -66,11 +71,19 @@ fn setup(
|
||||||
|
|
||||||
fn move_player(
|
fn move_player(
|
||||||
keys: Res<ButtonInput<KeyCode>>,
|
keys: Res<ButtonInput<KeyCode>>,
|
||||||
|
axes: Res<Axis<GamepadAxis>>,
|
||||||
|
gamepads: Res<ButtonInput<GamepadButton>>,
|
||||||
|
gamepad1: Option<Res<GamepadOne>>,
|
||||||
mut query: Query<(&mut Transform, &mut Velocity), With<Player>>,
|
mut query: Query<(&mut Transform, &mut Velocity), With<Player>>,
|
||||||
window: Query<&Window>,
|
window: Query<&Window>,
|
||||||
) {
|
) {
|
||||||
let (mut transform, mut velocity) = query.single_mut();
|
let (mut transform, mut velocity) = query.single_mut();
|
||||||
velocity.0 = Vec2::ZERO;
|
velocity.0 = Vec2::ZERO;
|
||||||
|
|
||||||
|
if let Some(gamepad) = gamepad1.as_deref() {
|
||||||
|
handle_gamepad_movement(&axes, gamepad, &gamepads, &mut velocity);
|
||||||
|
};
|
||||||
|
|
||||||
if keys.pressed(KeyCode::ArrowRight) {
|
if keys.pressed(KeyCode::ArrowRight) {
|
||||||
velocity.x += 1.0;
|
velocity.x += 1.0;
|
||||||
}
|
}
|
||||||
|
@ -95,3 +108,60 @@ fn move_player(
|
||||||
let screen_size: Vec3 = window.physical_size().as_vec2().extend(1.0);
|
let screen_size: Vec3 = window.physical_size().as_vec2().extend(1.0);
|
||||||
transform.translation = transform.translation.clamp(Vec3::ZERO, screen_size);
|
transform.translation = transform.translation.clamp(Vec3::ZERO, screen_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_gamepad_movement(
|
||||||
|
axes: &Axis<GamepadAxis>,
|
||||||
|
gamepad: &GamepadOne,
|
||||||
|
gamepads: &Res<ButtonInput<GamepadButton>>,
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue