Browse Source

Chapter 26 wrap up.

Herbert Wolverson 4 years ago
parent
commit
0f6bdc26d4

BIN
book/src/c26-s1.gif


BIN
book/src/c26-s2.gif


+ 81 - 0
book/src/chapter_26.md

@@ -241,6 +241,87 @@ This repeats until we have a lot of small rooms.
 
 You can `cargo run` the code right now, to see the rooms appearing.
 
+![Screenshot](./c26-s1.gif)
+
+## Adding some doorways
+
+It's all well and good to have rooms, but without doors connecting them it's not going to be a very fun experience! Fortunately, the *exact same code* from the previous chapter will work here, also.
+
+```rust
+// Now we want corridors
+for i in 0..self.rooms.len()-1 {
+    let room = self.rooms[i];
+    let next_room = self.rooms[i+1];
+    let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2))-1);
+    let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2))-1);
+    let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2))-1);
+    let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2))-1);
+    self.draw_corridor(start_x, start_y, end_x, end_y);
+    self.take_snapshot();
+}
+```
+
+This in turn calls the unchanged `draw_corridor` function:
+
+```rust
+fn draw_corridor(&mut self, x1:i32, y1:i32, x2:i32, y2:i32) {
+    let mut x = x1;
+    let mut y = y1;
+
+    while x != x2 || y != y2 {
+        if x < x2 {
+            x += 1;
+        } else if x > x2 {
+            x -= 1;
+        } else if y < y2 {
+            y += 1;
+        } else if y > y2 {
+            y -= 1;
+        }
+
+        let idx = self.map.xy_idx(x, y);
+        self.map.tiles[idx] = TileType::Floor;
+    }
+}
+```
+
+## Don't forget the stairs (I nearly did, AGAIN!)
+
+Finally, we need to wrap up and create the exit:
+
+```rust
+// Don't forget the stairs
+let stairs = self.rooms[self.rooms.len()-1].center();
+let stairs_idx = self.map.xy_idx(stairs.0, stairs.1);
+self.map.tiles[stairs_idx] = TileType::DownStairs;
+```
+
+We place the exit in the last room, guaranteeing that the poor player has a ways to walk.
+
+If you `cargo run` now, you'll see something like this:
+
+![Screenshot](./c26-s2.gif).
+
+## Restoring randomness - again
+
+Lastly, we go back to `map_builders/mod.rs` and edit our `random_builder` to once gain provide a random dungeon per level:
+
+```rust
+pub fn random_builder(new_depth: i32) -> Box<dyn MapBuilder> {
+    let mut rng = rltk::RandomNumberGenerator::new();
+    let builder = rng.roll_dice(1, 3);
+    match builder {
+        1 => Box::new(BspDungeonBuilder::new(new_depth)),
+        2 => Box::new(BspInteriorBuilder::new(new_depth))
+        _ => Box::new(SimpleMapBuilder::new(new_depth))
+    }
+}
+```
+
+## Wrap Up
+
+This type of dungeon can represent an interior, maybe of a space ship, a castle, or even a home. You can tweak dimensions, door placement, and bias the splitting as you see fit - but you'll get a map that makes most of the available space usable by the game. It's probably worth being sparing with these levels (or incorporating them into other levels) - they can lack variety, even though they are random.
+
 **The source code for this chapter may be found [here](https://github.com/thebracket/rustrogueliketutorial/tree/master/chapter-26-bsp-interiors)**
 
 

+ 1 - 1
chapter-26-bsp-interiors/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 > 500.0 {
+                if self.mapgen_timer > 200.0 {
                     self.mapgen_timer = 0.0;
                     self.mapgen_index += 1;
                     if self.mapgen_index == self.mapgen_history.len() {

+ 39 - 0
chapter-26-bsp-interiors/src/map_builders/bsp_interior.rs

@@ -85,6 +85,25 @@ impl BspInteriorBuilder {
             self.take_snapshot();
         }
 
+        // Now we want corridors
+        for i in 0..self.rooms.len()-1 {
+            let room = self.rooms[i];
+            let next_room = self.rooms[i+1];
+            let start_x = room.x1 + (rng.roll_dice(1, i32::abs(room.x1 - room.x2))-1);
+            let start_y = room.y1 + (rng.roll_dice(1, i32::abs(room.y1 - room.y2))-1);
+            let end_x = next_room.x1 + (rng.roll_dice(1, i32::abs(next_room.x1 - next_room.x2))-1);
+            let end_y = next_room.y1 + (rng.roll_dice(1, i32::abs(next_room.y1 - next_room.y2))-1);
+            self.draw_corridor(start_x, start_y, end_x, end_y);
+            self.take_snapshot();
+        }
+
+        // Don't forget the stairs
+        let stairs = self.rooms[self.rooms.len()-1].center();
+        let stairs_idx = self.map.xy_idx(stairs.0, stairs.1);
+        self.map.tiles[stairs_idx] = TileType::DownStairs;
+        self.take_snapshot();
+
+        // Place the player
         let start = self.rooms[0].center();
         self.starting_position = Position{ x: start.0, y: start.1 };
     }
@@ -121,4 +140,24 @@ impl BspInteriorBuilder {
             if half_height > MIN_ROOM_SIZE { self.add_subrects(v2, rng); }
         }
     }
+
+    fn draw_corridor(&mut self, x1:i32, y1:i32, x2:i32, y2:i32) {
+        let mut x = x1;
+        let mut y = y1;
+
+        while x != x2 || y != y2 {
+            if x < x2 {
+                x += 1;
+            } else if x > x2 {
+                x -= 1;
+            } else if y < y2 {
+                y += 1;
+            } else if y > y2 {
+                y -= 1;
+            }
+
+            let idx = self.map.xy_idx(x, y);
+            self.map.tiles[idx] = TileType::Floor;
+        }
+    }
 }

+ 4 - 4
chapter-26-bsp-interiors/src/map_builders/mod.rs

@@ -19,12 +19,12 @@ 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, 2);
+    let mut rng = rltk::RandomNumberGenerator::new();
+    let builder = rng.roll_dice(1, 3);
     match builder {
         1 => Box::new(BspDungeonBuilder::new(new_depth)),
+        2 => Box::new(BspInteriorBuilder::new(new_depth))
         _ => Box::new(SimpleMapBuilder::new(new_depth))
-    }*/
-    Box::new(BspInteriorBuilder::new(new_depth))
+    }
 }