aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGuillaume Pasquet <dev@etenil.net>2019-11-24 11:31:55 +0000
committerGuillaume Pasquet <dev@etenil.net>2019-11-24 11:31:55 +0000
commit4032fc8200980025b015c5f798de87a5918b798b (patch)
tree692544c2ca52009be18fd79e95a1e33646288c68
parentf14e0005f082b5d4cbca0f2e0d501ad15da3c856 (diff)
Line of sight work
-rw-r--r--src/state.rs2
-rw-r--r--src/tiling.rs65
2 files changed, 60 insertions, 7 deletions
diff --git a/src/state.rs b/src/state.rs
index be32228..8561486 100644
--- a/src/state.rs
+++ b/src/state.rs
@@ -6,7 +6,7 @@ use crate::entities::{Character, Entity, Player};
use crate::tiling::{tile_to_str, Tile, TileGrid, TileType};
use crate::world::{apply_movement, Dungeon, Generatable, Level, Movement};
-const PLAYER_SIGHT: usize = 5;
+const PLAYER_SIGHT: usize = 3;
pub struct State {
pub player: Character,
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));
}
}
}