Browse Source

Chapter 23 continued - more refactoring into dynamic builder land.

Herbert Wolverson 4 years ago
parent
commit
1a9e9dbd73

File diff suppressed because it is too large
+ 184 - 101
book/src/chapter_23.md


+ 16 - 12
chapter-23-generic-map/src/main.rs

@@ -306,20 +306,22 @@ impl State {
         }
 
         // Build a new map and place the player
+        let mut builder;
         let worldmap;
         let current_depth;
         let player_start;
         {
             let mut worldmap_resource = self.ecs.write_resource::<Map>();
             current_depth = worldmap_resource.depth;
-            let (newmap, start) = map_builders::build_random_map(current_depth + 1);
-            *worldmap_resource = newmap;
-            player_start = start;
+            builder = map_builders::random_builder(current_depth + 1);
+            builder.build_map();
+            *worldmap_resource = builder.get_map();
+            player_start = builder.get_starting_position();
             worldmap = worldmap_resource.clone();
         }
 
         // Spawn bad guys
-        map_builders::spawn(&worldmap, &mut self.ecs, current_depth+1);
+        builder.spawn_entities(&mut self.ecs);
 
         // Place the player and update resources
         let (player_x, player_y) = (player_start.x, player_start.y);
@@ -361,18 +363,17 @@ impl State {
         }
 
         // Build a new map and place the player
-        let worldmap;
+        let mut builder = map_builders::random_builder(1);
         let player_start;
         {
             let mut worldmap_resource = self.ecs.write_resource::<Map>();
-            let (newmap, start) = map_builders::build_random_map(1);
-            player_start = start;
-            *worldmap_resource = newmap;
-            worldmap = worldmap_resource.clone();
+            builder.build_map();
+            player_start = builder.get_starting_position();
+            *worldmap_resource = builder.get_map();
         }
 
         // Spawn bad guys
-        map_builders::spawn(&worldmap, &mut self.ecs, 1);
+        builder.spawn_entities(&mut self.ecs);
 
         // Place the player and update resources
         let (player_x, player_y) = (player_start.x, player_start.y);
@@ -442,13 +443,16 @@ fn main() {
 
     gs.ecs.insert(SimpleMarkerAllocator::<SerializeMe>::new());
 
-    let (map, player_start) = map_builders::build_random_map(1);
+    let mut builder = map_builders::random_builder(1);
+    builder.build_map();
+    let player_start = builder.get_starting_position();
+    let map = builder.get_map();
     let (player_x, player_y) = (player_start.x, player_start.y);
 
     let player_entity = spawner::player(&mut gs.ecs, player_x, player_y);
 
     gs.ecs.insert(rltk::RandomNumberGenerator::new());
-    map_builders::spawn(&map, &mut gs.ecs, 1);
+    builder.spawn_entities(&mut gs.ecs);
 
     gs.ecs.insert(map);
     gs.ecs.insert(Point::new(player_x, player_y));

+ 8 - 16
chapter-23-generic-map/src/map_builders/mod.rs

@@ -1,27 +1,19 @@
 use super::{Map, Rect, TileType, Position, spawner};
 mod simple_map;
 use simple_map::SimpleMapBuilder;
-mod bsp_dungeon;
-use bsp_dungeon::BspDungeonBuilder;
 mod common;
 use common::*;
 use specs::prelude::*;
 
-trait MapBuilder {
-    fn build(new_depth: i32) -> (Map, Position);
-    fn spawn(map : &Map, ecs : &mut World, new_depth: i32);
+pub trait MapBuilder {
+    fn build_map(&mut self);
+    fn spawn_entities(&mut self, ecs : &mut World);
+    fn get_map(&self) -> Map;
+    fn get_starting_position(&self) -> Position;
 }
 
-pub fn build_random_map(new_depth: i32) -> (Map, Position) {
-    let mut rng = rltk::RandomNumberGenerator::new();
-    let builder = rng.roll_dice(1, 2);
-    println!("Builder roll: {}", builder);
-    match builder {
-        2 => BspDungeonBuilder::build(new_depth),
-        _ => SimpleMapBuilder::build(new_depth)
-    }    
+pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
+    // Note that until we have a second map type, this isn't even slighlty random
+    Box::new(SimpleMapBuilder::new(new_depth))
 }
 
-pub fn spawn(map : &Map, ecs : &mut World, new_depth: i32) {
-    BspDungeonBuilder::spawn(map, ecs, new_depth);
-}

+ 43 - 25
chapter-23-generic-map/src/map_builders/simple_map.rs

@@ -4,24 +4,42 @@ use super::{MapBuilder, Map, Rect, apply_room_to_map,
 use rltk::RandomNumberGenerator;
 use specs::prelude::*;
 
-pub struct SimpleMapBuilder {}
+pub struct SimpleMapBuilder {
+    map : Map,
+    starting_position : Position,
+    depth: i32
+}
 
 impl MapBuilder for SimpleMapBuilder {
-    fn build(new_depth: i32) -> (Map, Position) {
-        let mut map = Map::new(new_depth);
-        let playerpos = SimpleMapBuilder::rooms_and_corridors(&mut map);
-        (map, playerpos)
+    fn get_map(&self) -> Map {
+        self.map.clone()
+    }
+
+    fn get_starting_position(&self) -> Position {
+        self.starting_position.clone()
+    }
+
+    fn build_map(&mut self) {
+        self.rooms_and_corridors();
     }
 
-    fn spawn(map : &Map, ecs : &mut World, new_depth: i32) {
-        for room in map.rooms.iter().skip(1) {
-            spawner::spawn_room(ecs, room, new_depth);
+    fn spawn_entities(&mut self, ecs : &mut World) {
+        for room in self.map.rooms.iter().skip(1) {
+            spawner::spawn_room(ecs, room, self.depth);
         }
     }
 }
 
 impl SimpleMapBuilder {
-    fn rooms_and_corridors(map : &mut Map) -> Position {
+    pub fn new(new_depth : i32) -> SimpleMapBuilder {
+        SimpleMapBuilder{
+            map : Map::new(new_depth),
+            starting_position : Position{ x: 0, y : 0 },
+            depth : new_depth
+        }
+    }
+
+    fn rooms_and_corridors(&mut self) {
         const MAX_ROOMS : i32 = 30;
         const MIN_SIZE : i32 = 6;
         const MAX_SIZE : i32 = 10;
@@ -31,37 +49,37 @@ impl SimpleMapBuilder {
         for _i in 0..MAX_ROOMS {
             let w = rng.range(MIN_SIZE, MAX_SIZE);
             let h = rng.range(MIN_SIZE, MAX_SIZE);
-            let x = rng.roll_dice(1, map.width - w - 1) - 1;
-            let y = rng.roll_dice(1, map.height - h - 1) - 1;
+            let x = rng.roll_dice(1, self.map.width - w - 1) - 1;
+            let y = rng.roll_dice(1, self.map.height - h - 1) - 1;
             let new_room = Rect::new(x, y, w, h);
             let mut ok = true;
-            for other_room in map.rooms.iter() {
+            for other_room in self.map.rooms.iter() {
                 if new_room.intersect(other_room) { ok = false }
             }
             if ok {
-                apply_room_to_map(map, &new_room);
+                apply_room_to_map(&mut self.map, &new_room);
 
-                if !map.rooms.is_empty() {
+                if !self.map.rooms.is_empty() {
                     let (new_x, new_y) = new_room.center();
-                    let (prev_x, prev_y) = map.rooms[map.rooms.len()-1].center();
+                    let (prev_x, prev_y) = self.map.rooms[self.map.rooms.len()-1].center();
                     if rng.range(0,1) == 1 {
-                        apply_horizontal_tunnel(map, prev_x, new_x, prev_y);
-                        apply_vertical_tunnel(map, prev_y, new_y, new_x);
+                        apply_horizontal_tunnel(&mut self.map, prev_x, new_x, prev_y);
+                        apply_vertical_tunnel(&mut self.map, prev_y, new_y, new_x);
                     } else {
-                        apply_vertical_tunnel(map, prev_y, new_y, prev_x);
-                        apply_horizontal_tunnel(map, prev_x, new_x, new_y);
+                        apply_vertical_tunnel(&mut self.map, prev_y, new_y, prev_x);
+                        apply_horizontal_tunnel(&mut self.map, prev_x, new_x, new_y);
                     }
                 }
 
-                map.rooms.push(new_room);
+                self.map.rooms.push(new_room);
             }
         }
 
-        let stairs_position = map.rooms[map.rooms.len()-1].center();
-        let stairs_idx = map.xy_idx(stairs_position.0, stairs_position.1);
-        map.tiles[stairs_idx] = TileType::DownStairs;
+        let stairs_position = self.map.rooms[self.map.rooms.len()-1].center();
+        let stairs_idx = self.map.xy_idx(stairs_position.0, stairs_position.1);
+        self.map.tiles[stairs_idx] = TileType::DownStairs;
 
-        let start_pos = map.rooms[0].center();
-        Position{ x: start_pos.0, y: start_pos.1 }
+        let start_pos = self.map.rooms[0].center();
+        self.starting_position = Position{ x: start_pos.0, y: start_pos.1 };
     }
 }