Skip to content

Commit

Permalink
feat: Player Plugin
Browse files Browse the repository at this point in the history
  • Loading branch information
DennisSmuda committed Feb 18, 2024
1 parent 7aee19c commit 401a692
Show file tree
Hide file tree
Showing 5 changed files with 163 additions and 54 deletions.
51 changes: 51 additions & 0 deletions src/components.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use bevy::prelude::*;
use rand::{
distributions::{Distribution, Standard},
Rng,
};

// Player Component
#[derive(Component)]
pub struct Player {
pub direction: MoveDirection,
pub speed: f32,
pub id: u32,
}

// Enemy Component
#[derive(Component)]
pub struct Enemy {
pub direction: MoveDirection,
pub speed: f32,
}

#[derive(Component)]
pub enum Collider {
Player,
Enemy,
}

// MoveDirection Component
#[derive(PartialEq, Copy, Clone)]
pub enum MoveDirection {
Left,
Up,
Right,
Down,
None,
}

///
/// Implement Distribution Trait to get a random direction
/// see => https://stackoverflow.com/questions/48490049/how-do-i-choose-a-random-value-from-an-enum
impl Distribution<MoveDirection> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> MoveDirection {
match rng.gen_range(0..=3) {
// rand 0.8
0 => MoveDirection::Up,
1 => MoveDirection::Down,
2 => MoveDirection::Right,
_ => MoveDirection::Left,
}
}
}
2 changes: 2 additions & 0 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
use bevy::prelude::Color;

pub const TIME_STEP: f32 = 1.0 / 60.0;

// Dimensions
pub const WINDOW_WIDTH: f32 = 800.;
pub const WINDOW_HEIGHT: f32 = 600.;
Expand Down
53 changes: 3 additions & 50 deletions src/game/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
use crate::*;

mod game_ui;

#[derive(Component)]
struct Player;
mod player;

#[derive(Component)]
struct Enemy;
Expand All @@ -15,31 +13,17 @@ pub struct GamePlugin;

impl Plugin for GamePlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::InGame), setup_game)
app.add_plugins(player::PlayerPlugin)
.add_systems(OnEnter(AppState::InGame), game_ui::setup)
.add_systems(Update, game_ui::update.run_if(in_state(AppState::InGame)))
.add_systems(Update, spawn_enemies.run_if(in_state(AppState::InGame)))
.add_systems(Update, move_enemies.run_if(in_state(AppState::InGame)))
.add_systems(Update, player_movement.run_if(in_state(AppState::InGame)))
.add_systems(Update, check_collisions.run_if(in_state(AppState::InGame)))
.add_systems(OnExit(AppState::InGame), teardown)
.add_systems(OnExit(AppState::InGame), game_ui::teardown);
}
}

fn setup_game(mut commands: Commands) {
commands
.spawn(SpriteBundle {
sprite: Sprite {
color: PLAYER_COLOR,
custom_size: Some(Vec2::new(16.0, 16.0)),
..Default::default()
},
..Default::default()
})
.insert(Player);
}

fn spawn_enemies(mut commands: Commands, time: Res<Time>, mut timer: ResMut<SpawnTimer>) {
if timer.0.tick(time.delta()).just_finished() {
// Determine spawn position and velocity here
Expand Down Expand Up @@ -87,39 +71,8 @@ fn check_collisions(
}
}

fn player_movement(
keyboard_input: Res<Input<KeyCode>>,
mut query: Query<&mut Transform, With<Player>>,
) {
for mut transform in query.iter_mut() {
let mut direction = Vec3::ZERO;

if keyboard_input.pressed(KeyCode::Left) {
direction.x -= 1.0;
}
if keyboard_input.pressed(KeyCode::Right) {
direction.x += 1.0;
}
if keyboard_input.pressed(KeyCode::Up) {
direction.y += 1.0;
}
if keyboard_input.pressed(KeyCode::Down) {
direction.y -= 1.0;
}

transform.translation += direction * TIME_STEP;
}
}

fn teardown(
mut commands: Commands,
entities: Query<Entity, With<Enemy>>,
players: Query<Entity, With<Player>>,
) {
fn teardown(mut commands: Commands, entities: Query<Entity, With<Enemy>>) {
for entity in entities.iter() {
commands.entity(entity).despawn_recursive();
}
for player in players.iter() {
commands.entity(player).despawn_recursive();
}
}
102 changes: 102 additions & 0 deletions src/game/player.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
use crate::*;

pub struct PlayerPlugin;

impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::InGame), setup_player)
.add_systems(Update, player_input.run_if(in_state(AppState::InGame)))
.add_systems(Update, player_movement.run_if(in_state(AppState::InGame)))
.add_systems(OnExit(AppState::InGame), teardown);
}
}

///
/// Player Setup
///
fn setup_player(mut commands: Commands) {
commands
.spawn(SpriteBundle {
sprite: Sprite {
color: PLAYER_COLOR,
custom_size: Some(Vec2::new(16.0, 16.0)),
..Default::default()
},
..Default::default()
})
.insert(Player {
speed: 250.0,
direction: MoveDirection::Up,
id: rand::random::<u32>(),
})
.insert(Collider::Player);
}

///
/// Player Movement
///
fn player_movement(mut players: Query<(&Player, &mut Transform)>) {
let (player, mut transform) = players.single_mut();
let translation = &mut transform.translation;
// println!("Player Input System: {}", player.id);

match &player.direction {
&MoveDirection::Left => {
translation.x -= player.speed * TIME_STEP;
}
MoveDirection::Right => {
translation.x += player.speed * TIME_STEP;
}
MoveDirection::Up => {
translation.y += player.speed * TIME_STEP;
}
MoveDirection::Down => {
translation.y -= player.speed * TIME_STEP;
}
MoveDirection::None => {
// println!("Stop")
}
}
// Keep in bounds
translation.x = translation.x.min(WINDOW_WIDTH / 2.).max(-WINDOW_WIDTH / 2.);
translation.y = translation
.y
.min(WINDOW_HEIGHT / 2.)
.max(-WINDOW_HEIGHT / 2.);
}

///
/// Player Input
///
pub fn player_input(
mut next_state: ResMut<NextState<AppState>>,
keyboard_input: Res<Input<KeyCode>>,
mut players: Query<&mut Player>,
) {
if let Some(mut player) = players.iter_mut().next() {
let dir: MoveDirection =
if keyboard_input.pressed(KeyCode::Up) || keyboard_input.pressed(KeyCode::K) {
MoveDirection::Up
} else if keyboard_input.pressed(KeyCode::Down) || keyboard_input.pressed(KeyCode::J) {
MoveDirection::Down
} else if keyboard_input.pressed(KeyCode::Left) || keyboard_input.pressed(KeyCode::H) {
MoveDirection::Left
} else if keyboard_input.pressed(KeyCode::Right) || keyboard_input.pressed(KeyCode::L) {
MoveDirection::Right
} else {
MoveDirection::None
};

player.direction = dir;
}

if keyboard_input.pressed(KeyCode::Escape) {
next_state.set(AppState::GameOver)
}
}

fn teardown(mut commands: Commands, players: Query<Entity, With<Player>>) {
for player in players.iter() {
commands.entity(player).despawn_recursive();
}
}
9 changes: 5 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,21 @@ use bevy::window::WindowResolution;
mod constants;
use constants::*;

mod gameover;
use gameover::GameOverPlugin;
mod components;
use components::*;

mod game;
use game::GamePlugin;

mod gameover;
use gameover::GameOverPlugin;

#[derive(Resource)]
struct SpawnTimer(Timer);

#[derive(Resource)]
struct ScoreTimer(Timer);

const TIME_STEP: f32 = 5.0;

#[derive(Debug, Clone, Copy, Default, Eq, PartialEq, Hash, States)]
pub enum AppState {
#[default]
Expand Down

0 comments on commit 401a692

Please sign in to comment.