diff --git a/src/assets/mod.rs b/src/assets/mod.rs index 8401aa2..f07ece9 100644 --- a/src/assets/mod.rs +++ b/src/assets/mod.rs @@ -4,7 +4,7 @@ use bevy::prelude::*; use bevy_asset_loader::prelude::*; use iyes_progress::{ProgressCounter, ProgressPlugin}; -use crate::{state::FadeReset, AppState}; +use crate::AppState; pub mod audio; pub mod fonts; @@ -42,7 +42,7 @@ fn add_dynamic_assets( ); } -fn fade_to_splash(progress: Res, mut fade_reset: ResMut) { +fn fade_to_splash(progress: Res, mut fade_reset: ResMut>) { let progress = progress.progress(); if progress.total > 0 && progress.done == progress.total { fade_reset.set(if cfg!(debug_assertions) { diff --git a/src/level/level.rs b/src/level/level.rs index e0f079d..c390501 100644 --- a/src/level/level.rs +++ b/src/level/level.rs @@ -1,11 +1,11 @@ use bevy::prelude::*; use bevy_rapier2d::prelude::*; -use super::mapgen::{gen_map, TileType}; +use super::map::TileType; use crate::{ agent::agent::AgentRotation, assets::textures::TextureAssets, echolocation::echolocation::EcholocationHitColor, enemy::SpawnEnemyEv, palette::COL_PORTAL, - player::player::PlayerEv, render::camera::PrimaryCamera, AppSize, + player::player::PlayerEv, }; #[derive(Component)] @@ -20,38 +20,14 @@ pub struct ReachedLevel(pub usize); #[derive(Component)] pub struct Wall; -pub(super) fn setup_test_lvl( +pub(super) fn setup_level( mut cmd: Commands, mut ev_w: EventWriter, - reached: Res, - bounds: Res, - mut camera_transform: Query<&mut Transform, With>, tex: Res, + map: Res, ) { - let tile_size = 40.0; + let tile_size = super::TILE_SIZE; let half_ts = tile_size / 2.; - let map_scale = 16. + 6. * reached.0 as f32; - let map_size = (Vec2::new(16.0f32, 12.0f32).normalize() * map_scale).as_ivec2(); - let physical_map_size = map_size.as_vec2() * tile_size; - let map: super::mapgen::Map; - loop { - if let Some(good_map) = gen_map(map_size.x, map_size.y) { - let wall_count = good_map - .tiles - .iter() - .filter(|&x| x == &TileType::Wall) - .count(); - if wall_count as f32 / (good_map.tiles.len() as f32) < 0.6 { - map = good_map; - break; - } - } - } - - camera_transform.single_mut().translation = - (Vec2::new(map.width as f32, map.height as f32) * half_ts).extend(999.9); - let scale_factor = (physical_map_size / bounds.0).max_element(); - camera_transform.single_mut().scale = Vec2::splat(scale_factor).extend(1.0); for y in 0..map.height { for x in 0..map.width { @@ -93,6 +69,7 @@ pub(super) fn setup_test_lvl( .insert(Name::new("Exit")); } &TileType::PlayerSpawn => { + bevy::log::info!("Requesting player spawn"); cmd.spawn(TransformBundle::from_transform(Transform::from_xyz( x, y, 0., ))) diff --git a/src/level/mapgen.rs b/src/level/map.rs similarity index 91% rename from src/level/mapgen.rs rename to src/level/map.rs index 63ea2cc..4da1832 100644 --- a/src/level/mapgen.rs +++ b/src/level/map.rs @@ -1,4 +1,4 @@ -use bevy::prelude::IVec2; +use bevy::prelude::{IVec2, Resource}; use bracket_algorithm_traits::prelude::{BaseMap, SmallVec}; use bracket_geometry::prelude::{DistanceAlg, Point}; use bracket_pathfinding::prelude::DijkstraMap; @@ -17,7 +17,7 @@ pub enum TileType { Enemy(EnemyType), } -#[derive(Default, Clone)] +#[derive(Default, Clone, Resource)] pub struct Map { pub tiles: Vec, pub width: i32, @@ -103,7 +103,7 @@ const NEIGHBORS: [[i32; 2]; 8] = [ ]; const ADJACENTS: [[i32; 2]; 4] = [[-1, 0], [1, 0], [0, -1], [0, 1]]; -pub fn gen_map(width: i32, height: i32) -> Option { +pub fn generate(width: i32, height: i32, difficulty: usize) -> Option { let mut map = Map::new(width, height, move |_x, _y| { if rand::random::() > 0.55 { TileType::Floor @@ -175,6 +175,7 @@ pub fn gen_map(width: i32, height: i32) -> Option { map.tiles[start_idx] = TileType::PlayerSpawn; // Set enemy spawns + let mut follow_spawns = vec![]; for y in 1..map.height - 1 { for x in 1..map.width - 1 { // First, the static ones @@ -192,10 +193,17 @@ pub fn gen_map(width: i32, height: i32) -> Option { let idx = map.xy_idx(x, y); if map.get_pathing_distance(idx, start_idx) > 2.0 { *map.xy_mut(x, y) = TileType::Enemy(EnemyType::FollowPing); + follow_spawns.push((x, y)); } } } } + // Remove followers if there's too many + let max_follow_spawns: usize = difficulty.pow(2); + while follow_spawns.len() > max_follow_spawns { + let (x, y) = follow_spawns.swap_remove(rand::random::() % follow_spawns.len()); + *map.xy_mut(x, y) = TileType::Floor; + } // Set goal spawn let mut idx = 0usize; diff --git a/src/level/mod.rs b/src/level/mod.rs index b54001e..61b246c 100644 --- a/src/level/mod.rs +++ b/src/level/mod.rs @@ -1,14 +1,62 @@ use bevy::prelude::*; -use crate::state::AppState; +use crate::{render::camera::PrimaryCamera, state::AppState, AppSize}; -use self::level::{setup_test_lvl, update_score, ReachedLevel}; +use self::{ + level::{setup_level, update_score, ReachedLevel}, + map::TileType, +}; pub mod level; -pub mod mapgen; +pub mod map; + +pub use map::Map; +pub const TILE_SIZE: f32 = 40.; +pub const HALF_TILE_SIZE: f32 = 20.; pub fn lvl_plugin(app: &mut App) { app.init_resource::() - .add_system(setup_test_lvl.in_schedule(OnEnter(AppState::Game))) + .insert_resource(Map::default()) + .add_systems( + (update_map, setup_level, sync_camera) + .chain() + .in_schedule(OnEnter(AppState::Game)), + ) + .add_system( + sync_camera + .run_if(resource_changed::()) + .in_set(OnUpdate(AppState::Game)), + ) .add_system(update_score); } + +pub fn update_map(mut map_resource: ResMut, reached: Res) { + bevy::log::info!("Creating map"); + let map_scale = 16. + 4. * reached.0 as f32; + let map_size = (Vec2::new(16.0f32, 12.0f32).normalize() * map_scale).as_ivec2(); + loop { + if let Some(new_map) = map::generate(map_size.x, map_size.y, reached.0) { + let wall_count = new_map + .tiles + .iter() + .filter(|&x| x == &TileType::Wall) + .count(); + if wall_count as f32 / (new_map.tiles.len() as f32) < 0.6 { + *map_resource = new_map; + break; + } + } + } +} + +pub fn sync_camera( + map: Res, + bounds: Res, + mut camera_transform: Query<&mut Transform, With>, +) { + let physical_map_size = IVec2::new(map.width, map.height).as_vec2() * TILE_SIZE; + camera_transform.single_mut().translation = + (Vec2::new(map.width as f32, map.height as f32) * HALF_TILE_SIZE).extend(999.9); + let scale_factor = (physical_map_size / bounds.0).max_element(); + camera_transform.single_mut().scale = Vec2::splat(scale_factor).extend(1.0); +} diff --git a/src/player/player.rs b/src/player/player.rs index cbe3d10..c98dbed 100644 --- a/src/player/player.rs +++ b/src/player/player.rs @@ -37,6 +37,7 @@ pub(super) fn spawn_player( let radius = 20.; if let Some(transform) = entry_q.iter().next() { + bevy::log::info!("Spawning player"); cmd.spawn(SpatialBundle::from_transform(*transform)) .insert(RigidBody::KinematicPositionBased) .insert(Collider::ball(radius * 0.8)) diff --git a/src/state/reset.rs b/src/state/reset.rs index 47bae32..bd3507c 100644 --- a/src/state/reset.rs +++ b/src/state/reset.rs @@ -17,7 +17,7 @@ pub struct PersistReset; pub struct FadeNode; #[derive(Resource, Deref, DerefMut)] -pub struct FadeReset(Option); +pub struct FadeReset(pub Option); impl FadeReset { pub fn set(&mut self, state: AppState) {