refactored player into own plugin :D

This commit is contained in:
2024-11-02 12:20:57 +02:00
parent 156be812fc
commit adcffb7fcc
2 changed files with 84 additions and 142 deletions

View File

@@ -1,24 +1,18 @@
use bevy::{prelude::*, utils::HashSet}; use bevy::prelude::*;
use bevy_ecs_ldtk::prelude::*; use bevy_ecs_ldtk::prelude::*;
use player::{Player, PlayerPlugin};
mod player;
fn main() { fn main() {
App::new() App::new()
.add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest())) .add_plugins(DefaultPlugins.set(ImagePlugin::default_nearest()))
.add_plugins(LdtkPlugin) .add_plugins(LdtkPlugin)
.add_plugins(PlayerPlugin)
.add_systems(Update, (translate_grid_coords_entities, check_goal))
.insert_resource(LevelSelection::index(0)) .insert_resource(LevelSelection::index(0))
.register_ldtk_entity::<PlayerBundle>("Player")
.init_resource::<LevelWalls>()
.register_ldtk_entity::<GoalBundle>("Goal") .register_ldtk_entity::<GoalBundle>("Goal")
.register_ldtk_int_cell::<WallBundle>(1) .register_ldtk_int_cell::<WallBundle>(1)
.add_systems(
Update,
(
move_player_from_input,
translate_grid_coords_entities,
cache_wall_locations,
check_goal,
),
)
.add_systems(Startup, setup) .add_systems(Startup, setup)
.run(); .run();
} }
@@ -35,17 +29,6 @@ fn setup(mut commands: Commands, asset_server: Res<AssetServer>) {
..Default::default() ..Default::default()
}); });
} }
#[derive(Default, Component)]
struct Player;
#[derive(Default, Bundle, LdtkEntity)]
struct PlayerBundle {
player: Player,
#[sprite_sheet_bundle]
sprite_bundle: LdtkSpriteSheetBundle,
#[grid_coords]
grid_coords: GridCoords,
}
#[derive(Default, Component)] #[derive(Default, Component)]
struct Goal; struct Goal;
@@ -58,32 +41,8 @@ struct GoalBundle {
#[grid_coords] #[grid_coords]
grid_coords: GridCoords, grid_coords: GridCoords,
} }
fn move_player_from_input(
mut players: Query<&mut GridCoords, With<Player>>,
input: Res<ButtonInput<KeyCode>>,
level_walls: Res<LevelWalls>,
) {
let movement_direction = if input.just_pressed(KeyCode::KeyW) {
GridCoords::new(0, 1)
} else if input.just_pressed(KeyCode::KeyA) {
GridCoords::new(-1, 0)
} else if input.just_pressed(KeyCode::KeyS) {
GridCoords::new(0, -1)
} else if input.just_pressed(KeyCode::KeyD) {
GridCoords::new(1, 0)
} else {
return;
};
for mut player_grid_coords in players.iter_mut() {
let destination = *player_grid_coords + movement_direction;
if !level_walls.in_wall(&destination) {
*player_grid_coords = destination;
}
}
}
const GRID_SIZE: i32 = 16;
pub const GRID_SIZE: i32 = 16;
fn translate_grid_coords_entities( fn translate_grid_coords_entities(
mut grid_coords_entities: Query<(&mut Transform, &GridCoords), Changed<GridCoords>>, mut grid_coords_entities: Query<(&mut Transform, &GridCoords), Changed<GridCoords>>,
) { ) {
@@ -102,50 +61,6 @@ struct WallBundle {
wall: Wall, wall: Wall,
} }
#[derive(Default, Resource)]
struct LevelWalls {
wall_locations: HashSet<GridCoords>,
level_width: i32,
level_height: i32,
}
impl LevelWalls {
fn in_wall(&self, grid_coords: &GridCoords) -> bool {
grid_coords.x < 0
|| grid_coords.y < 0
|| grid_coords.x >= self.level_width
|| grid_coords.y >= self.level_height
|| self.wall_locations.contains(grid_coords)
}
}
fn cache_wall_locations(
mut level_walls: ResMut<LevelWalls>,
mut level_events: EventReader<LevelEvent>,
walls: Query<&GridCoords, With<Wall>>,
ldtk_project_entities: Query<&Handle<LdtkProject>>,
ldtk_project_assets: Res<Assets<LdtkProject>>,
) {
for level_event in level_events.read() {
if let LevelEvent::Spawned(level_iid) = level_event {
let ldtk_project = ldtk_project_assets
.get(ldtk_project_entities.single())
.expect("LdtkProject should be loaded when level is spawned");
let level = ldtk_project
.get_raw_level_by_iid(level_iid.get())
.expect("spawned level should exist in project");
let wall_locations = walls.iter().copied().collect();
let new_level_walls = LevelWalls {
wall_locations,
level_width: level.px_wid / GRID_SIZE,
level_height: level.px_hei / GRID_SIZE,
};
*level_walls = new_level_walls;
}
}
}
fn check_goal( fn check_goal(
level_selection: ResMut<LevelSelection>, level_selection: ResMut<LevelSelection>,
players: Query<&GridCoords, (With<Player>, Changed<GridCoords>)>, players: Query<&GridCoords, (With<Player>, Changed<GridCoords>)>,

View File

@@ -1,60 +1,57 @@
use bevy::prelude::*; use bevy::{prelude::*, utils::HashSet};
use bevy_ecs_ldtk::prelude::*; use bevy_ecs_ldtk::prelude::*;
use bevy_rapier2d::dynamics::Velocity;
use crate::{climbing::Climber, inventory::Inventory}; use crate::{Wall, GRID_SIZE};
use crate::{colliders::ColliderBundle, ground_detection::GroundDetection};
#[derive(Copy, Clone, Eq, PartialEq, Debug, Default, Component)] #[derive(Default, Component)]
pub struct Player; pub(crate) struct Player;
#[derive(Clone, Default, Bundle, LdtkEntity)] #[derive(Default, Bundle, LdtkEntity)]
pub struct PlayerBundle { struct PlayerBundle {
#[sprite_bundle("player.png")] player: Player,
pub sprite_bundle: SpriteBundle, #[sprite_sheet_bundle]
#[from_entity_instance] sprite_bundle: LdtkSpriteSheetBundle,
pub collider_bundle: ColliderBundle, #[grid_coords]
pub player: Player, grid_coords: GridCoords,
#[worldly]
pub worldly: Worldly,
pub climber: Climber,
pub ground_detection: GroundDetection,
// Build Items Component manually by using `impl From<&EntityInstance>`
#[from_entity_instance]
items: Inventory,
// The whole EntityInstance can be stored directly as an EntityInstance component
#[from_entity_instance]
entity_instance: EntityInstance,
} }
pub fn player_movement( #[derive(Default, Resource)]
struct LevelWalls {
wall_locations: HashSet<GridCoords>,
level_width: i32,
level_height: i32,
}
impl LevelWalls {
fn in_wall(&self, grid_coords: &GridCoords) -> bool {
grid_coords.x < 0
|| grid_coords.y < 0
|| grid_coords.x >= self.level_width
|| grid_coords.y >= self.level_height
|| self.wall_locations.contains(grid_coords)
}
}
fn move_player_from_input(
mut players: Query<&mut GridCoords, With<Player>>,
input: Res<ButtonInput<KeyCode>>, input: Res<ButtonInput<KeyCode>>,
mut query: Query<(&mut Velocity, &mut Climber, &GroundDetection), With<Player>>, level_walls: Res<LevelWalls>,
) { ) {
for (mut velocity, mut climber, ground_detection) in &mut query { let movement_direction = if input.just_pressed(KeyCode::KeyW) {
let right = if input.pressed(KeyCode::KeyD) { 1. } else { 0. }; GridCoords::new(0, 1)
let left = if input.pressed(KeyCode::KeyA) { 1. } else { 0. }; } else if input.just_pressed(KeyCode::KeyA) {
GridCoords::new(-1, 0)
} else if input.just_pressed(KeyCode::KeyS) {
GridCoords::new(0, -1)
} else if input.just_pressed(KeyCode::KeyD) {
GridCoords::new(1, 0)
} else {
return;
};
velocity.linvel.x = (right - left) * 200.; for mut player_grid_coords in players.iter_mut() {
let destination = *player_grid_coords + movement_direction;
if climber.intersecting_climbables.is_empty() { if !level_walls.in_wall(&destination) {
climber.climbing = false; *player_grid_coords = destination;
} else if input.just_pressed(KeyCode::KeyW) || input.just_pressed(KeyCode::KeyS) {
climber.climbing = true;
}
if climber.climbing {
let up = if input.pressed(KeyCode::KeyW) { 1. } else { 0. };
let down = if input.pressed(KeyCode::KeyS) { 1. } else { 0. };
velocity.linvel.y = (up - down) * 200.;
}
if input.just_pressed(KeyCode::Space) && (ground_detection.on_ground || climber.climbing) {
velocity.linvel.y = 500.;
climber.climbing = false;
} }
} }
} }
@@ -63,7 +60,37 @@ pub struct PlayerPlugin;
impl Plugin for PlayerPlugin { impl Plugin for PlayerPlugin {
fn build(&self, app: &mut App) { fn build(&self, app: &mut App) {
app.add_systems(Update, player_movement) app.add_systems(Update, (move_player_from_input, cache_wall_locations))
.register_ldtk_entity::<PlayerBundle>("Player"); .register_ldtk_entity::<PlayerBundle>("Player")
.init_resource::<LevelWalls>();
}
}
fn cache_wall_locations(
mut level_walls: ResMut<LevelWalls>,
mut level_events: EventReader<LevelEvent>,
walls: Query<&GridCoords, With<Wall>>,
ldtk_project_entities: Query<&Handle<LdtkProject>>,
ldtk_project_assets: Res<Assets<LdtkProject>>,
) {
for level_event in level_events.read() {
if let LevelEvent::Spawned(level_iid) = level_event {
let ldtk_project = ldtk_project_assets
.get(ldtk_project_entities.single())
.expect("LdtkProject should be loaded when level is spawned");
let level = ldtk_project
.get_raw_level_by_iid(level_iid.get())
.expect("spawned level should exist in project");
let wall_locations = walls.iter().copied().collect();
let new_level_walls = LevelWalls {
wall_locations,
level_width: level.px_wid / GRID_SIZE,
level_height: level.px_hei / GRID_SIZE,
};
*level_walls = new_level_walls;
}
} }
} }