aboutsummaryrefslogtreecommitdiff
path: root/src/tiling.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/tiling.rs')
-rw-r--r--src/tiling.rs65
1 files changed, 59 insertions, 6 deletions
diff --git a/src/tiling.rs b/src/tiling.rs
index 9319a94..f2a9b02 100644
--- a/src/tiling.rs
+++ b/src/tiling.rs
@@ -103,13 +103,66 @@ impl TileGrid {
self.ysize
}
- pub fn clear_fog_of_war(&mut self, center: &(usize, usize), radius: usize) {
- let startx: usize = 0.max(center.0 as isize - radius as isize) as usize;
- let starty: usize = 0.max(center.1 as isize - radius as isize) as usize;
- for x in startx..self.xsize.min(center.0 + radius) {
- for y in starty..self.ysize.min(center.1 + radius) {
- self.grid[y][x].visibility(true)
+ /// Clears all blocks in a single line of sight ray; stop when encountering a wall
+ /// This uses the bresenham algorithm, see:
+ /// https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm
+ fn clear_los(&mut self, start: &(usize, usize), end: &(usize, usize)) {
+ let dx = (end.0 as isize - start.0 as isize).abs();
+ let sx: isize = if start.0 < end.0 { 1 } else { -1 };
+ let dy = -(end.1 as isize - start.1 as isize).abs();
+ let sy: isize = if start.1 < end.1 { 1 } else { -1 };
+ let mut err = dx + dy;
+
+ let mut x = start.0;
+ let mut y = start.1;
+
+ loop {
+ if x == end.0 && y == end.1 {
+ break;
+ }
+ if let TileType::Wall = self.grid[y][x].get_type() {
+ break;
+ }
+
+ let err2 = 2 * err;
+ if err2 >= dy {
+ err += dy;
+ x = (x as isize + sx).max(0) as usize;
+ }
+ if err2 <= dx {
+ err += dx;
+ y = (y as isize + sy).max(0) as usize;
}
+ self.grid[y][x].visibility(true);
+ }
+ }
+
+ /// Walk around the perimeter of the line of sight and ray-trace to clear tiles
+ /// up to the nearest obstacle.
+ pub fn clear_fog_of_war(&mut self, center: &(usize, usize), radius: usize) {
+ let a = (
+ center.0.saturating_sub(radius),
+ center.1.saturating_sub(radius),
+ );
+ let b = (center.0 + radius, center.1.saturating_sub(radius));
+ let c = (center.0 + radius, center.1 + radius);
+ let d = (center.0.saturating_sub(radius), center.1 + radius);
+
+ // From a to b
+ for x in a.0..b.0 {
+ self.clear_los(center, &(x, a.1));
+ }
+ // From b to c
+ for y in b.1..c.1 {
+ self.clear_los(center, &(b.0, y));
+ }
+ // From c to d
+ for x in d.0..c.0 {
+ self.clear_los(center, &(x, c.1));
+ }
+ // From d to a
+ for y in a.1..d.1 {
+ self.clear_los(center, &(d.0, y));
}
}
}