From 49f045db75b476a01f3c473b749f9ce4ead2bbe2 Mon Sep 17 00:00:00 2001 From: tobi Date: Sun, 2 Jun 2024 22:15:57 +0200 Subject: [PATCH] Add kernel size fade in --- src/config.rs | 10 +++-- src/generator.rs | 98 +++++++++++++++++++++++++++++++++++++++++---- src/map.rs | 102 ++++++++++------------------------------------- src/rendering.rs | 4 +- src/walker.rs | 42 ++++++++++++++----- 5 files changed, 151 insertions(+), 105 deletions(-) diff --git a/src/config.rs b/src/config.rs index fb925a0..60ceea4 100644 --- a/src/config.rs +++ b/src/config.rs @@ -115,12 +115,13 @@ pub struct GenerationConfig { /// TODO: pub pulse_straight_delay: usize, - - /// TODO: pub pulse_corner_delay: usize, + pub pulse_max_kernel_size: usize, /// TODO: - pub pulse_max_kernel_size: usize, + pub fade_steps: usize, + pub fade_max_size: usize, + pub fade_min_size: usize, } impl GenerationConfig { @@ -197,6 +198,9 @@ impl Default for GenerationConfig { pulse_corner_delay: 5, pulse_straight_delay: 10, pulse_max_kernel_size: 4, + fade_steps: 60, + fade_max_size: 6, + fade_min_size: 3, } } } diff --git a/src/generator.rs b/src/generator.rs index bd4df3a..0c56362 100644 --- a/src/generator.rs +++ b/src/generator.rs @@ -5,14 +5,14 @@ use crate::{ config::{GenerationConfig, MapConfig}, debug::DebugLayer, kernel::Kernel, - map::{BlockType, Map}, + map::{BlockType, Map, Overwrite}, position::Position, post_processing as post, random::{Random, Seed}, walker::CuteWalker, }; -use macroquad::color::colors; +use macroquad::{color::colors, miniquad::conf}; pub fn print_time(timer: &Timer, message: &str) { println!("{}: {:?}", message, timer.elapsed()); @@ -30,6 +30,75 @@ pub struct Generator { spawn: Position, } +pub fn generate_room( + map: &mut Map, + pos: &Position, + room_size: usize, + platform_margin: usize, + zone_type: Option<&BlockType>, +) -> Result<(), &'static str> { + let room_size: i32 = room_size as i32; + let platform_margin: i32 = platform_margin as i32; + + if !map.pos_in_bounds(&pos.shifted_by(room_size + 2, room_size + 1).unwrap()) + || !map.pos_in_bounds(&pos.shifted_by(room_size + 1, room_size + 1).unwrap()) + { + return Err("generate room out of bounds"); + } + + // carve room + map.set_area_border( + &pos.shifted_by(-room_size, -room_size)?, + &pos.shifted_by(room_size, room_size)?, + &BlockType::Empty, + &Overwrite::Force, + ); + + // only reserve - 1 so that when this is used for platforms + map.set_area( + &pos.shifted_by(-room_size + 1, -room_size + 1)?, + &pos.shifted_by(room_size - 1, room_size - 1)?, + &BlockType::EmptyReserved, + &Overwrite::Force, + ); + + // set spawns + if zone_type == Some(&BlockType::Start) { + map.set_area( + &pos.shifted_by(-(room_size - platform_margin), room_size - 1)?, + &pos.shifted_by(room_size - platform_margin, room_size - 1)?, + &BlockType::Spawn, + &Overwrite::Force, + ); + } + + if let Some(zone_type) = zone_type { + map.set_area_border( + &pos.shifted_by(-room_size - 1, -room_size - 1)?, + &pos.shifted_by(room_size + 1, room_size + 1)?, + zone_type, + &Overwrite::ReplaceNonSolidForce, + ); + + map.set_area( + &pos.shifted_by(-(room_size - platform_margin), room_size + 1)?, + &pos.shifted_by(room_size - platform_margin, room_size + 1)?, + &BlockType::Platform, + &Overwrite::Force, + ); + } else { + // set center platform + map.set_area( + &pos.shifted_by(-(room_size - platform_margin), room_size - 3)?, + &pos.shifted_by(room_size - platform_margin, room_size - 3)?, + &BlockType::Platform, + &Overwrite::Force, + ); + } + + Ok(()) +} + impl Generator { /// derive a initial generator state based on a GenerationConfig pub fn new(gen_config: &GenerationConfig, map_config: &MapConfig, seed: Seed) -> Generator { @@ -71,7 +140,16 @@ impl Generator { config.validate()?; // randomly mutate kernel - self.walker.mutate_kernel(config, &mut self.rnd); + if self.walker.steps > config.fade_steps { + self.walker.mutate_kernel(config, &mut self.rnd); + } else { + self.walker.set_fade_kernel( + self.walker.steps, + config.fade_min_size, + config.fade_max_size, + config.fade_steps, + ); + } // perform one step self.walker @@ -95,12 +173,16 @@ impl Generator { self.debug_layers.get_mut("edge_bugs").unwrap().grid = edge_bugs; print_time(&timer, "fix edge bugs"); - self.map - .generate_room(&self.spawn, 4, 3, Some(&BlockType::Start)) + generate_room(&mut self.map, &self.spawn, 6, 3, Some(&BlockType::Start)) .expect("start room generation failed"); - self.map - .generate_room(&self.walker.pos.clone(), 4, 3, Some(&BlockType::Finish)) - .expect("start finish room generation"); + generate_room( + &mut self.map, + &self.walker.pos.clone(), + 4, + 3, + Some(&BlockType::Finish), + ) + .expect("start finish room generation"); print_time(&timer, "place rooms"); if config.min_freeze_size > 0 { diff --git a/src/map.rs b/src/map.rs index d20636d..17bde97 100644 --- a/src/map.rs +++ b/src/map.rs @@ -40,13 +40,23 @@ impl BlockType { } pub enum Overwrite { - /// will replace EVERYTHING + /// Replace EVERYTHING Force, + /// Replace Hookable+Freeze ReplaceSolidFreeze, + + /// Replace Hookable ReplaceSolidOnly, + + /// Replace Empty ReplaceEmptyOnly, + + /// Replace Freeze+Empty ReplaceNonSolid, + + /// Replace Freeze+Empty+EmptyReserved + ReplaceNonSolidForce, } impl Overwrite { @@ -59,6 +69,10 @@ impl Overwrite { Overwrite::ReplaceSolidOnly => matches!(&btype, BlockType::Hookable), Overwrite::ReplaceEmptyOnly => matches!(&btype, BlockType::Empty), Overwrite::ReplaceNonSolid => matches!(&btype, BlockType::Freeze | BlockType::Empty), + Overwrite::ReplaceNonSolidForce => matches!( + &btype, + BlockType::Freeze | BlockType::Empty | BlockType::EmptyReserved + ), } } } @@ -106,11 +120,11 @@ impl Map { } } - pub fn update( + pub fn apply_kernel( &mut self, walker: &CuteWalker, kernel: &Kernel, - kernel_type: KernelType, + block_type: BlockType, ) -> Result<(), &'static str> { let offset: usize = kernel.size / 2; // offset of kernel wrt. position (top/left) let extend: usize = kernel.size - offset; // how much kernel extends position (bot/right) @@ -121,7 +135,7 @@ impl Map { let exceeds_lower_bound = (walker.pos.y + extend) > self.height; if exceeds_left_bound || exceeds_upper_bound || exceeds_right_bound || exceeds_lower_bound { - return Err("kernel out of bounds"); + return Err("Kernel out of bounds"); } let root_pos = Position::new(walker.pos.x - offset, walker.pos.y - offset); @@ -130,17 +144,9 @@ impl Map { if *kernel_active { let current_type = &self.grid[absolute_pos.as_index()]; - let new_type = match (&kernel_type, current_type) { - // inner kernel removes everything - (KernelType::Inner, BlockType::Hookable) => Some(BlockType::Empty), - (KernelType::Inner, BlockType::Freeze) => Some(BlockType::Empty), - - // outer kernel will turn hookables to freeze - (KernelType::Outer, BlockType::Hookable) => Some(BlockType::Freeze), - (KernelType::Outer, BlockType::Freeze) => Some(BlockType::Freeze), - - // ignore everything else - (_, _) => None, + let new_type = match current_type { + BlockType::Hookable | BlockType::Freeze => Some(block_type.clone()), + _ => None, }; if let Some(new_type) = new_type { @@ -155,72 +161,6 @@ impl Map { Ok(()) } - pub fn generate_room( - &mut self, - pos: &Position, - room_size: usize, - platform_margin: usize, - zone_type: Option<&BlockType>, - ) -> Result<(), &'static str> { - if pos.x < (room_size + 1) - || pos.y < (room_size + 1) - || pos.x > self.width - (room_size + 1) - || pos.y > self.height - (room_size + 1) - { - return Err("generate room out of bounds"); - } - - // TODO: i feel like this is utterly stupid - let room_size: i32 = room_size.to_i32().unwrap(); - let platform_margin: i32 = platform_margin.to_i32().unwrap(); - - // carve room - self.set_area_border( - &pos.shifted_by(-room_size, -room_size)?, - &pos.shifted_by(room_size, room_size)?, - &BlockType::Empty, - &Overwrite::Force, - ); - - let inner_room_size = room_size - 1; - assert!(inner_room_size > 0); - self.set_area( - &pos.shifted_by(-inner_room_size, -inner_room_size)?, - &pos.shifted_by(inner_room_size, inner_room_size)?, - &BlockType::EmptyReserved, - &Overwrite::Force, - ); - - // set platform - self.set_area( - &pos.shifted_by(-(room_size - platform_margin), room_size - 3)?, - &pos.shifted_by(room_size - platform_margin, room_size - 3)?, - &BlockType::Platform, - &Overwrite::Force, - ); - - // set spawns - if zone_type == Some(&BlockType::Start) { - self.set_area( - &pos.shifted_by(-(room_size - platform_margin), room_size - 4)?, - &pos.shifted_by(room_size - platform_margin, room_size - 4)?, - &BlockType::Spawn, - &Overwrite::Force, - ); - } - // set start/finish line - if let Some(zone_type) = zone_type { - self.set_area_border( - &pos.shifted_by(-room_size - 1, -room_size - 1)?, - &pos.shifted_by(room_size + 1, room_size + 1)?, - zone_type, - &Overwrite::ReplaceNonSolid, - ); - } - - Ok(()) - } - fn pos_to_chunk_pos(&self, pos: Position) -> Position { Position::new(pos.x / self.chunk_size, pos.y / self.chunk_size) } diff --git a/src/rendering.rs b/src/rendering.rs index 9fabf61..8b32ec2 100644 --- a/src/rendering.rs +++ b/src/rendering.rs @@ -12,8 +12,8 @@ fn blocktype_to_color(value: &BlockType) -> Color { BlockType::EmptyReserved => Color::new(0.3, 0.0, 0.0, 0.1), BlockType::Finish => Color::new(1.0, 0.1, 0.1, 0.8), BlockType::Start => Color::new(0.1, 1.0, 0.1, 0.8), - BlockType::Spawn => Color::new(0.5, 0.5, 0.0, 0.8), - BlockType::Platform => Color::new(0.2, 0.2, 0.7, 0.8), + BlockType::Platform => Color::new(0.5, 0.5, 0.0, 0.8), + BlockType::Spawn => Color::new(0.2, 0.2, 0.7, 0.8), } } diff --git a/src/walker.rs b/src/walker.rs index 79015ec..87155ed 100644 --- a/src/walker.rs +++ b/src/walker.rs @@ -1,7 +1,6 @@ -use macroquad::miniquad::conf; - use crate::{ config::{GenerationConfig, MapConfig}, + generator, kernel::Kernel, map::{BlockType, KernelType, Map, Overwrite}, position::{Position, ShiftDirection}, @@ -87,8 +86,7 @@ impl CuteWalker { // Case 2: max distance has been exceeded -> force platform using a room if self.steps_since_platform > max_distance { - // TODO: for now this is hardcoded so that platform is shifted down by 6 blocks. - map.generate_room(&walker_pos.shifted_by(0, 6)?, 5, 3, None)?; + generator::generate_room(map, &walker_pos.shifted_by(0, 6)?, 5, 3, None)?; self.steps_since_platform = 0; return Ok(()); } @@ -104,7 +102,7 @@ impl CuteWalker { &walker_pos.shifted_by(-1, 0)?, &walker_pos.shifted_by(1, 0)?, &BlockType::Platform, - &Overwrite::ReplaceSolidFreeze, + &Overwrite::ReplaceEmptyOnly, ); self.steps_since_platform = 0; } @@ -151,19 +149,25 @@ impl CuteWalker { if perform_pulse { self.pulse_counter = 0; // reset pulse counter - map.update( + map.apply_kernel( self, &Kernel::new(&self.inner_kernel.size + 4, 0.0), - KernelType::Outer, + BlockType::Freeze, )?; - map.update( + map.apply_kernel( self, &Kernel::new(&self.inner_kernel.size + 2, 0.0), - KernelType::Inner, + BlockType::EmptyReserved, )?; } else { - map.update(self, &self.outer_kernel, KernelType::Outer)?; - map.update(self, &self.inner_kernel, KernelType::Inner)?; + map.apply_kernel(self, &self.outer_kernel, BlockType::Freeze)?; + + let empty = if self.steps < config.fade_steps { + BlockType::EmptyReserved + } else { + BlockType::Empty + }; + map.apply_kernel(self, &self.inner_kernel, empty)?; }; // apply kernels @@ -183,6 +187,22 @@ impl CuteWalker { println!("Cute walker was cuddled!"); } + /// fades kernel size from max_size to min_size for fade_steps + pub fn set_fade_kernel( + &mut self, + step: usize, + min_size: usize, + max_size: usize, + fade_steps: usize, + ) { + let slope = (min_size as f32 - max_size as f32) / fade_steps as f32; + let kernel_size_f = (step as f32) * slope + max_size as f32; + let kernel_size = kernel_size_f.floor() as usize; + dbg!(step, kernel_size_f, kernel_size); + self.inner_kernel = Kernel::new(kernel_size, 0.0); + self.outer_kernel = Kernel::new(kernel_size + 2, 0.0); + } + pub fn mutate_kernel(&mut self, config: &GenerationConfig, rnd: &mut Random) { let mut inner_size = self.inner_kernel.size; let mut inner_circ = self.inner_kernel.circularity;