Made wall smoothness adjustable
[kaka/rust-sdl-test.git] / src / core / level / lvlgen.rs
index d2a389e..4a22807 100644 (file)
@@ -6,19 +6,25 @@ use rand::Rng;
 
 ////////// LEVEL GENERATOR /////////////////////////////////////////////////////
 
-#[derive(Default)]
+#[derive(Debug, Default)]
 pub struct LevelGenerator {
     pub seed: u32,
     pub iterations: u8,
+    pub wall_smooth_radius: u8,
 }
 
 impl LevelGenerator {
-    pub fn new(seed: u32, iterations: u8) -> Self{
-       LevelGenerator { seed, iterations }
+    pub fn new(seed: u32) -> Self{
+       LevelGenerator {
+           seed,
+           iterations: 5,
+           wall_smooth_radius: 2,
+       }
     }
 
     pub fn generate(&self) -> Level {
-       time_scope!("grid generation");
+       println!("new level from {:?}", self);
+       time_scope!("level generation");
 
        let cell_size = 20;
        let (width, height) = (2560 / cell_size, 1440 / cell_size);
@@ -56,13 +62,13 @@ impl LevelGenerator {
     }
 
     #[allow(dead_code)]
-    fn simplex_noise(&self, grid: &mut Grid) {
+    fn simplex_noise(&self, grid: &mut Grid<bool>) {
        let noise = OpenSimplex::new().set_seed(self.seed);
        self.set_each(grid, |x, y| noise.get([x as f64 / 12.0, y as f64 / 12.0]) > 0.055, 1);
     }
 
     #[allow(dead_code)]
-    fn random_noise(&self, grid: &mut Grid) {
+    fn random_noise(&self, grid: &mut Grid<bool>) {
        let mut rng: rand::prelude::StdRng = rand::SeedableRng::seed_from_u64(self.seed as u64);
        let noise = OpenSimplex::new().set_seed(self.seed);
        self.set_each(grid, |_x, _y| rng.gen_range(0, 100) > (45 + (150.0 * noise.get([_x as f64 / 40.0, _y as f64 / 10.0])) as usize), 1); // more horizontal platforms
@@ -71,7 +77,7 @@ impl LevelGenerator {
     }
 
     #[allow(dead_code)]
-    fn smooth(&self, grid: &mut Grid) {
+    fn smooth(&self, grid: &mut Grid<bool>) {
        let distance = 1;
        for _i in 0..self.iterations {
            let mut next = vec!(vec!(true; grid.height); grid.width);
@@ -93,7 +99,7 @@ impl LevelGenerator {
     }
 
     #[allow(dead_code)]
-    fn smooth_until_equilibrium(&self, grid: &mut Grid) {
+    fn smooth_until_equilibrium(&self, grid: &mut Grid<bool>) {
        let distance = 1;
        let mut count = 0;
        loop {
@@ -114,7 +120,7 @@ impl LevelGenerator {
                grid.cells = next;
            }
        }
-       println!("{} iterations needed", count);
+       println!("  {} iterations needed", count);
     }
 
     fn neighbours(&self, grid: &Vec<Vec<bool>>, px: usize, py: usize, distance: usize) -> u8 {
@@ -129,7 +135,7 @@ impl LevelGenerator {
        count
     }
 
-    fn set_each<F: FnMut(usize, usize) -> bool>(&self, grid: &mut Grid, mut func: F, walls: usize) {
+    fn set_each<F: FnMut(usize, usize) -> bool>(&self, grid: &mut Grid<bool>, mut func: F, walls: usize) {
        for x in walls..(grid.width - walls) {
            for y in walls..(grid.height - walls) {
                grid.cells[x][y] = func(x, y);
@@ -137,7 +143,7 @@ impl LevelGenerator {
        }
     }
 
-    fn subdivide(&self, grid: &mut Grid) -> Grid {
+    fn subdivide(&self, grid: &mut Grid<bool>) -> Grid<bool> {
        let (width, height) = (grid.width * 2, grid.height * 2);
        let mut cells = vec!(vec!(true; height); width);
        for x in 1..(width - 1) {
@@ -153,8 +159,8 @@ impl LevelGenerator {
        }
     }
 
-    fn find_regions(&self, grid: &Grid) -> Vec<Region> {
-       time_scope!("finding all regions");
+    fn find_regions(&self, grid: &Grid<bool>) -> Vec<Region> {
+       time_scope!("  finding all regions");
        let mut regions = vec!();
        let mut marked = vec!(vec!(false; grid.height); grid.width);
        for x in 0..grid.width {
@@ -167,7 +173,7 @@ impl LevelGenerator {
        regions
     }
 
-    fn get_region_at_point(&self, grid: &Grid, x: usize, y: usize, marked: &mut Vec<Vec<bool>>) -> Region {
+    fn get_region_at_point(&self, grid: &Grid<bool>, x: usize, y: usize, marked: &mut Vec<Vec<bool>>) -> Region {
        let value = grid.cells[x][y];
        let mut cells = vec!();
        let mut queue = vec!((x, y));
@@ -190,22 +196,22 @@ impl LevelGenerator {
        Region { value, cells }
     }
 
-    fn delete_region(&self, grid: &mut Grid, region: &Region) {
+    fn delete_region(&self, grid: &mut Grid<bool>, region: &Region) {
        for c in &region.cells {
            grid.cells[c.0][c.1] = !region.value;
        }
     }
 
-    fn filter_regions(&self, grid: &mut Grid) {
+    fn filter_regions(&self, grid: &mut Grid<bool>) {
        let min_wall_size = 0.0015;
-       println!("grid size: ({}, {}) = {} cells", grid.width, grid.height, grid.width * grid.height);
-       println!("min wall size: {}", (grid.width * grid.height) as f64 * min_wall_size);
+       println!("  grid size: ({}, {}) = {} cells", grid.width, grid.height, grid.width * grid.height);
+       println!("  min wall size: {}", (grid.width * grid.height) as f64 * min_wall_size);
 
        // delete all smaller wall regions
        for r in self.find_regions(grid).iter().filter(|r| r.value) {
            let percent = r.cells.len() as f64 / (grid.width * grid.height) as f64;
            if percent < min_wall_size {
-               // println!("delete wall region of size {}", r.cells.len());
+               // println!("  delete wall region of size {}", r.cells.len());
                self.delete_region(grid, r);
            }
        }
@@ -220,7 +226,7 @@ impl LevelGenerator {
        }
     }
 
-    fn find_walls(&self, grid: &Grid) -> Vec<Vec<Point<isize>>> {
+    fn find_walls(&self, grid: &Grid<bool>) -> Vec<Vec<Point<isize>>> {
        let mut walls = vec!();
        for r in self.find_regions(&grid) {
            if r.value {
@@ -264,13 +270,13 @@ impl Region {
        let mut outline = vec!();
        let mut directions = vec!((1, 0), (1, 1), (0, 1), (-1, 1), (-1, 0), (-1, -1), (0, -1), (1, -1)); // 8 directions rotating right from starting direction right
 
-       let mut p = self.find_first_point_of_outline(&rect, &grid);
+       let start = self.find_first_point_of_outline(&rect, &grid);
+       let mut p = start;
        marked[p.x as usize][p.y as usize] = true;
        loop {
            outline.push((p + (ox as isize, oy as isize)) * scale as isize);
            self.find_next_point_of_outline(&grid, &mut p, &mut directions);
-           if marked[p.x as usize][p.y as usize] {
-               // we're back at the beginning
+           if p == start {
                break;
            }
            marked[p.x as usize][p.y as usize] = true;