Browse Source

Minimally working DLA.

Herbert Wolverson 4 years ago
parent
commit
7911dd5a58

+ 9 - 0
Cargo.lock

@@ -500,6 +500,15 @@ dependencies = [
 [[package]]
 name = "chapter-30-dla"
 version = "0.1.0"
+dependencies = [
+ "rltk 0.4.1 (git+https://github.com/thebracket/rltk_rs)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
+ "specs 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "specs-derive 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wasm-bindgen 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)",
+ "web-sys 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)",
+]
 
 [[package]]
 name = "cloudabi"

+ 3 - 0
book/src/SUMMARY.md

@@ -33,4 +33,7 @@
     - [Drunkard's Walk Maps](./chapter_28.md)
     - [Mazes and Labyrinths](./chapter_29.md)
     - [Diffusion-limited aggregation maps](./chapter_30.md)
+    - Voronoi
+    - Noise
+    - Quantum Waveform Collapse
 [Contributors](./contributors.md)

+ 3 - 0
book/src/chapter_30.md

@@ -12,6 +12,9 @@
 
 See this [excellent article on Rogue Basin](http://www.roguebasin.com/index.php?title=Diffusion-limited_aggregation).
 
+Scaffolding
+
+
 
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-30-dla)**
 

+ 1 - 1
chapter-30-dla/src/main.rs

@@ -137,7 +137,7 @@ impl GameState for State {
                 draw_map(&self.mapgen_history[self.mapgen_index], ctx);
 
                 self.mapgen_timer += ctx.frame_time_ms;
-                if self.mapgen_timer > 400.0 {
+                if self.mapgen_timer > 20.0 {
                     self.mapgen_timer = 0.0;
                     self.mapgen_index += 1;
                     if self.mapgen_index == self.mapgen_history.len() {

+ 118 - 0
chapter-30-dla/src/map_builders/dla.rs

@@ -0,0 +1,118 @@
+use super::{MapBuilder, Map,  
+    TileType, Position, spawner, SHOW_MAPGEN_VISUALIZER,
+    remove_unreachable_areas_returning_most_distant, generate_voronoi_spawn_regions};
+use rltk::RandomNumberGenerator;
+use specs::prelude::*;
+use std::collections::HashMap;
+
+pub struct DLABuilder {
+    map : Map,
+    starting_position : Position,
+    depth: i32,
+    history: Vec<Map>,
+    noise_areas : HashMap<i32, Vec<usize>>
+}
+
+impl MapBuilder for DLABuilder {
+    fn get_map(&self) -> Map {
+        self.map.clone()
+    }
+
+    fn get_starting_position(&self) -> Position {
+        self.starting_position.clone()
+    }
+
+    fn get_snapshot_history(&self) -> Vec<Map> {
+        self.history.clone()
+    }
+
+    fn build_map(&mut self)  {
+        self.build();
+    }
+
+    fn spawn_entities(&mut self, ecs : &mut World) {
+        for area in self.noise_areas.iter() {
+            spawner::spawn_region(ecs, area.1, self.depth);
+        }
+    }
+
+    fn take_snapshot(&mut self) {
+        if SHOW_MAPGEN_VISUALIZER {
+            let mut snapshot = self.map.clone();
+            for v in snapshot.revealed_tiles.iter_mut() {
+                *v = true;
+            }
+            self.history.push(snapshot);
+        }
+    }
+}
+
+impl DLABuilder {
+    pub fn new(new_depth : i32) -> DLABuilder {
+        DLABuilder{
+            map : Map::new(new_depth),
+            starting_position : Position{ x: 0, y : 0 },
+            depth : new_depth,
+            history: Vec::new(),
+            noise_areas : HashMap::new()
+        }
+    }
+
+    #[allow(clippy::map_entry)]
+    fn build(&mut self) {
+        let mut rng = RandomNumberGenerator::new();
+
+        // DLA goes here
+
+        // Carve a starting seed
+        self.starting_position = Position{ x: self.map.width/2, y : self.map.height/2 };
+        let start_idx = self.map.xy_idx(self.starting_position.x, self.starting_position.y);
+        self.take_snapshot();
+        self.map.tiles[start_idx] = TileType::Floor;
+        self.map.tiles[start_idx-1] = TileType::Floor;
+        self.map.tiles[start_idx+1] = TileType::Floor;
+        self.map.tiles[start_idx-self.map.width as usize] = TileType::Floor;
+        self.map.tiles[start_idx+self.map.width as usize] = TileType::Floor;
+
+        // Random walker
+        let total_tiles = self.map.width * self.map.height;
+        let desired_floor_tiles = (total_tiles / 4) as usize;
+        let mut floor_tile_count = self.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
+        while floor_tile_count  < desired_floor_tiles {
+            let mut digger_x = rng.roll_dice(1, self.map.width - 3) + 1;
+            let mut digger_y = rng.roll_dice(1, self.map.height - 3) + 1;
+            let mut prev_x = digger_x;
+            let mut prev_y = digger_y;
+            let mut digger_idx = self.map.xy_idx(digger_x, digger_y);
+            while self.map.tiles[digger_idx] == TileType::Wall {
+                prev_x = digger_x;
+                prev_y = digger_y;
+                let stagger_direction = rng.roll_dice(1, 4);
+                match stagger_direction {
+                    1 => { if digger_x > 2 { digger_x -= 1; } }
+                    2 => { if digger_x < self.map.width-2 { digger_x += 1; } }
+                    3 => { if digger_y > 2 { digger_y -=1; } }
+                    _ => { if digger_y < self.map.height-2 { digger_y += 1; } }
+                }
+                digger_idx = self.map.xy_idx(digger_x, digger_y);
+            }
+            let prev_idx = self.map.xy_idx(prev_x, prev_y);
+            self.map.tiles[prev_idx] = TileType::Floor;
+
+            self.take_snapshot();
+
+            floor_tile_count = self.map.tiles.iter().filter(|a| **a == TileType::Floor).count();
+        }
+
+        // Find all tiles we can reach from the starting point
+        let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx);
+        self.take_snapshot();
+
+        // Place the stairs
+        self.map.tiles[exit_tile] = TileType::DownStairs;
+        self.take_snapshot();
+
+        // Now we build a noise map for use in spawning entities later
+        self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
+    }
+}

+ 5 - 1
chapter-30-dla/src/map_builders/mod.rs

@@ -11,6 +11,8 @@ mod drunkard;
 use drunkard::*;
 mod maze;
 use maze::*;
+mod dla;
+use dla::*;
 mod common;
 use common::*;
 use specs::prelude::*;
@@ -25,6 +27,7 @@ pub trait MapBuilder {
 }
 
 pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
+    /*
     let mut rng = rltk::RandomNumberGenerator::new();
     let builder = rng.roll_dice(1, 8);
     match builder {
@@ -36,6 +39,7 @@ pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
         6 => Box::new(DrunkardsWalkBuilder::winding_passages(new_depth)),
         7 => Box::new(MazeBuilder::new(new_depth)),
         _ => Box::new(SimpleMapBuilder::new(new_depth))
-    }    
+    }*/
+    Box::new(DLABuilder::new(new_depth))
 }
 

+ 1 - 0
wasmbuild.bat

@@ -28,6 +28,7 @@ CALL :Stage chapter-26-bsp-interiors
 CALL :Stage chapter-27-cellular-automota
 CALL :Stage chapter-28-drunkards-walk
 CALL :Stage chapter-29-mazes
+CALL :Stage chapter-30-dla
 
 REM Publish or perish
 cd book\book\wasm