From 4032fc8200980025b015c5f798de87a5918b798b Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Sun, 24 Nov 2019 11:31:55 +0000 Subject: Line of sight work --- src/state.rs | 2 +- src/tiling.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++------ 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)); } } } -- cgit v1.2.3 From 61efc432f5b6cbd3b580bdb330507661a3213222 Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Thu, 2 Jan 2020 15:19:35 +0000 Subject: Add line of sight --- Cargo.lock | 325 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 + src/main.rs | 39 ++++--- src/tiling.rs | 27 +++-- 4 files changed, 373 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 544bfbb..a59e743 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,15 +1,68 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "backtrace" +version = "0.3.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blake2b_simd" +version = "0.5.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "c2-chacha" version = "0.2.2" @@ -19,11 +72,48 @@ dependencies = [ "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cc" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cfg-if" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "chrono" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossterm" version = "0.13.3" @@ -44,6 +134,51 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "fuchsia-zircon" version = "0.3.3" @@ -148,11 +283,44 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ppv-lite86" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "proc-macro2" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rand" version = "0.7.0" @@ -175,6 +343,19 @@ dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand_core" version = "0.5.0" @@ -191,16 +372,80 @@ dependencies = [ "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_users" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "roguelike" version = "0.1.0" dependencies = [ "crossterm 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)", "ignore-result 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "simplelog 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", "text_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "simplelog" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "slab" version = "0.4.2" @@ -211,11 +456,56 @@ name = "spin" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "syn" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "text_io" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.8" @@ -255,12 +545,29 @@ dependencies = [ ] [metadata] +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum crossterm 0.13.3 (registry+https://github.com/rust-lang/crates.io-index)" = "759f2256ab248ad498bdd62038187450921b1b8d24c348d198f3425b0bd289cb" "checksum crossterm_winapi 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02de3a35bcabb5bb6dc7d4449abb546d23f123b06f074e2cf1c50db516da6ac8" +"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" @@ -273,14 +580,32 @@ dependencies = [ "checksum mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "83f51996a3ed004ef184e16818edc51fadffe8e7ca68be67f9dee67d84d0ff23" "checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum proc-macro2 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "0319972dcae462681daf4da1adeeaa066e3ebd29c69be96c6abb1259d2ee2bcc" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" +"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum simplelog 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "05a3e303ace6adb0a60a9e9e2fbc6a33e1749d1e43587e2125f7efa9c5e107c5" "checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" +"checksum syn 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ddc157159e2a7df58cd67b1cace10b8ed256a404fb0070593f137d8ba6bef4de" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum text_io 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "9658b61ebd1d2a40c276ba2335890b9eb6550b67458a6fbce2022e58c3350a50" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/Cargo.toml b/Cargo.toml index bf635a7..1255fad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,5 @@ rand = "0.7.0" text_io = "0.1.7" crossterm = "0.13.3" ignore-result = "0.2.0" +log = "0.4" +simplelog = "0.7" diff --git a/src/main.rs b/src/main.rs index e45701a..d00db53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,23 +1,22 @@ -extern crate crossterm; -extern crate ignore_result; -extern crate rand; -extern crate text_io; - mod entities; mod state; mod tiling; mod world; +use std::env; +use std::fs::File; +use std::io::{stdout, Write}; + use crossterm::cursor; use crossterm::execute; use crossterm::input::{input, InputEvent, KeyEvent}; use crossterm::screen::{EnterAlternateScreen, LeaveAlternateScreen, RawScreen}; use crossterm::terminal; -use entities::Player; use ignore_result::Ignore; +use simplelog::*; + +use entities::Player; use state::State; -use std::env; -use std::io::{stdout, Write}; use world::{Dungeon, DOWN, LEFT, RIGHT, UP}; fn player_name() -> String { @@ -28,23 +27,35 @@ fn player_name() -> String { } fn main() { + // Set up the debug logger only if required. + if let Ok(_val) = env::var("DEBUG") { + WriteLogger::init( + LevelFilter::Debug, + Config::default(), + File::create("roguerust.log").unwrap(), + ) + .unwrap(); + } + + // Initialise the terminal, the raw alternate mode allows direct character + // seeking and hides the prompt. let term_size = terminal::size().unwrap(); + execute!(stdout(), EnterAlternateScreen).unwrap(); + execute!(stdout(), cursor::Hide).unwrap(); + let _raw = RawScreen::into_raw_mode(); + // Initialise state, create the player and dungeon let mut state = State::new( Player::new(player_name(), String::from("Warrior"), 30, 10, 10, 20), Dungeon::new(term_size.0 as usize, (term_size.1 - 2) as usize, 5), ); - state.init(); - execute!(stdout(), EnterAlternateScreen).unwrap(); - execute!(stdout(), cursor::Hide).unwrap(); - - let _raw = RawScreen::into_raw_mode(); - let input = input(); let mut reader = input.read_sync(); + // Main loop, dispatches events and calls rendering routines. Don't + // add any game logic here. loop { state.render_player(); state.render_level(); diff --git a/src/tiling.rs b/src/tiling.rs index f2a9b02..17e8f32 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -1,3 +1,4 @@ +use log::debug; use std::convert::From; #[derive(Clone)] @@ -103,6 +104,10 @@ impl TileGrid { self.ysize } + fn reveal(&mut self, x: usize, y: usize) { + 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 @@ -116,11 +121,15 @@ impl TileGrid { let mut x = start.0; let mut y = start.1; + // the tile we're standing on needs to be visible. + self.reveal(start.0, start.1); + loop { if x == end.0 && y == end.1 { + self.reveal(x, y); break; } - if let TileType::Wall = self.grid[y][x].get_type() { + if let TileType::Empty = self.grid[y][x].get_type() { break; } @@ -133,7 +142,7 @@ impl TileGrid { err += dx; y = (y as isize + sy).max(0) as usize; } - self.grid[y][x].visibility(true); + self.reveal(x, y); } } @@ -148,20 +157,26 @@ impl TileGrid { let c = (center.0 + radius, center.1 + radius); let d = (center.0.saturating_sub(radius), center.1 + radius); + debug!("LOS: {:?} - {:?} {:?} {:?} {:?}", center, a, b, c, d); + // From a to b - for x in a.0..b.0 { + for x in a.0..=b.0 { + // debug!("Clear LOS from {:?} to {:?}", center, (x, a.1)); self.clear_los(center, &(x, a.1)); } // From b to c - for y in b.1..c.1 { + for y in b.1..=c.1 { + // debug!("Clear LOS from {:?} to {:?}", center, (b.0, y)); self.clear_los(center, &(b.0, y)); } // From c to d - for x in d.0..c.0 { + for x in d.0..=c.0 { + // debug!("Clear LOS from {:?} to {:?}", center, (x, c.1)); self.clear_los(center, &(x, c.1)); } // From d to a - for y in a.1..d.1 { + for y in a.1..=d.1 { + // debug!("Clear LOS from {:?} to {:?}", center, (d.0, y)); self.clear_los(center, &(d.0, y)); } } -- cgit v1.2.3 From bc3edb0c0337ca0fbf0398ba721aba55a09022e1 Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Fri, 3 Jan 2020 16:21:29 +0000 Subject: Change tests to not use #[should_panic] for travis --- src/world.rs | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/src/world.rs b/src/world.rs index 507e6b8..af72513 100644 --- a/src/world.rs +++ b/src/world.rs @@ -310,7 +310,11 @@ impl Level { corridor.tile(&mut grid)?; } - grid.set_tile(self.entrance.0, self.entrance.1, Tile::from(TileType::StairsUp)); + grid.set_tile( + self.entrance.0, + self.entrance.1, + Tile::from(TileType::StairsUp), + ); grid.set_tile(self.exit.0, self.exit.1, Tile::from(TileType::StairsDown)); Ok(grid) @@ -426,20 +430,18 @@ impl Generatable for Level { let room = &self.rooms[rng.gen_range(0, self.rooms.len() - 1)]; // Create the enemy - self.entities.push(Box::::new( - Enemy::new( - String::from("snake"), - 2 * self.depth as i32, - (2.0 * self.depth as f32 * 0.6).round() as i32, - (20.0 * self.depth as f32 * 0.2).max(80.0).round() as i32, - 0, - ( - room.start.0 + rng.gen_range(0, room.width), - room.start.1 + rng.gen_range(0, room.height), - ), - "s", - ) - )); + self.entities.push(Box::::new(Enemy::new( + String::from("snake"), + 2 * self.depth as i32, + (2.0 * self.depth as f32 * 0.6).round() as i32, + (20.0 * self.depth as f32 * 0.2).max(80.0).round() as i32, + 0, + ( + room.start.0 + rng.gen_range(0, room.width), + room.start.1 + rng.gen_range(0, room.height), + ), + "s", + ))); } } } @@ -467,15 +469,19 @@ mod tests { } #[test] - #[should_panic] fn test_make_corridor_with_overlapping_points_should_panic() { - Corridor::make((0, 0), (0, 0)).unwrap(); + match Corridor::make((0, 0), (0, 0)) { + Ok(_) => assert!(false), + Err(_) => assert!(true), + }; } #[test] - #[should_panic] fn test_make_corridor_with_misaligned_points_should_panic() { - Corridor::make((3, 3), (5, 5)).unwrap(); + match Corridor::make((3, 3), (5, 5)) { + Ok(_) => assert!(false), + Err(_) => assert!(true), + }; } #[test] -- cgit v1.2.3 From bcb72351df57b0bee8e080875287d81a37804153 Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Mon, 9 Mar 2020 09:30:14 +0000 Subject: Added unit tests for LOS --- src/tiling.rs | 124 +++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 118 insertions(+), 6 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index 17e8f32..a48d57e 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -1,7 +1,7 @@ use log::debug; use std::convert::From; -#[derive(Clone)] +#[derive(Clone, Debug)] pub enum TileType { Empty, Wall, @@ -12,7 +12,7 @@ pub enum TileType { Player, } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Tile { tile_type: TileType, visible: bool, @@ -64,7 +64,7 @@ impl TileGrid { for _ in 0..ysize { let mut subvec = Vec::with_capacity(xsize); for _ in 0..xsize { - subvec.push(Tile::new(TileType::Empty, true)); + subvec.push(Tile::new(TileType::Empty, false)); } grid.grid.push(subvec); } @@ -92,7 +92,12 @@ impl TileGrid { &self.grid } + pub fn tile_at(&self, x: usize, y: usize) -> &Tile { + &self.grid[y][x] + } + pub fn block_at(&self, x: usize, y: usize) -> &Tile { + //Needed to integrate with the terminal numbering &self.grid[y + 1][x] } @@ -125,11 +130,12 @@ impl TileGrid { self.reveal(start.0, start.1); loop { - if x == end.0 && y == end.1 { - self.reveal(x, y); + if let TileType::Empty = self.tile_at(x, y).get_type() { break; } - if let TileType::Empty = self.grid[y][x].get_type() { + + if x == end.0 && y == end.1 { + // self.reveal(x, y); break; } @@ -201,3 +207,109 @@ pub fn tile_to_str(tile: &Tile) -> &str { pub trait Tileable { fn tile(&self, grid: &mut TileGrid) -> Result<(), String>; } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn new_tilegrid_is_populated_by_empty_invisible_tiles() { + const GRID_SIZE: usize = 2; + let grid = TileGrid::new(GRID_SIZE, GRID_SIZE); + for x in 0..2 { + for y in 0..2 { + assert!(match grid.tile_at(x, y).tile_type { + TileType::Empty => true, + _ => false, + }); + assert_eq!(grid.tile_at(x, y).is_visible(), false); + } + } + } + + #[test] + fn tiles_can_be_revealed() { + let mut tile = Tile::new(TileType::Wall, false); + assert_eq!(tile.visible, false); + assert_eq!(tile.is_visible(), false); + tile.visibility(true); + assert_eq!(tile.visible, true); + assert_eq!(tile.is_visible(), true); + } + + #[test] + fn tilegrid_can_reveal_tiles() { + let mut grid = TileGrid::new(1, 1); + grid.reveal(0, 0); + assert_eq!(grid.grid[0][0].is_visible(), true); + assert_eq!(grid.tile_at(0, 0).is_visible(), true); + } + + #[test] + fn test_clear_los_clears_to_wall_on_vertical_up() { + let mut grid = TileGrid::new(9, 9); + grid.set_tile(5, 1, Tile::from(TileType::Wall)); + grid.set_tile(5, 2, Tile::from(TileType::Floor)); + grid.set_tile(5, 3, Tile::from(TileType::Floor)); + + grid.clear_los(&(5, 3), &(5, 0)); + assert_eq!(grid.tile_at(5, 4).is_visible(), false); + assert_eq!(grid.tile_at(5, 3).is_visible(), true); + assert_eq!(grid.tile_at(6, 2).is_visible(), false); + assert_eq!(grid.tile_at(5, 2).is_visible(), true); + assert_eq!(grid.tile_at(4, 2).is_visible(), false); + assert_eq!(grid.tile_at(5, 1).is_visible(), true); + assert_eq!(grid.tile_at(5, 0).is_visible(), false); + } + + #[test] + fn test_clear_los_clears_to_wall_on_vertical_down() { + let mut grid = TileGrid::new(9, 9); + grid.set_tile(5, 3, Tile::from(TileType::Wall)); + grid.set_tile(5, 2, Tile::from(TileType::Floor)); + grid.set_tile(5, 1, Tile::from(TileType::Floor)); + + grid.clear_los(&(5, 1), &(5, 4)); + assert_eq!(grid.tile_at(5, 0).is_visible(), false); + assert_eq!(grid.tile_at(4, 1).is_visible(), false); + assert_eq!(grid.tile_at(5, 1).is_visible(), true); + assert_eq!(grid.tile_at(6, 1).is_visible(), false); + assert_eq!(grid.tile_at(5, 2).is_visible(), true); + assert_eq!(grid.tile_at(5, 3).is_visible(), true); + assert_eq!(grid.tile_at(5, 4).is_visible(), false); + } + + #[test] + fn test_clear_los_clears_to_wall_on_horizontal_right() { + let mut grid = TileGrid::new(9, 9); + grid.set_tile(3, 5, Tile::from(TileType::Wall)); + grid.set_tile(2, 5, Tile::from(TileType::Floor)); + grid.set_tile(1, 5, Tile::from(TileType::Floor)); + + grid.clear_los(&(1, 5), &(4, 5)); + assert_eq!(grid.tile_at(0, 5).is_visible(), false); + assert_eq!(grid.tile_at(1, 5).is_visible(), true); + assert_eq!(grid.tile_at(2, 4).is_visible(), false); + assert_eq!(grid.tile_at(2, 5).is_visible(), true); + assert_eq!(grid.tile_at(2, 6).is_visible(), false); + assert_eq!(grid.tile_at(3, 5).is_visible(), true); + assert_eq!(grid.tile_at(3, 6).is_visible(), false); + } + + #[test] + fn test_clear_los_clears_to_wall_on_horizontal_left() { + let mut grid = TileGrid::new(9, 9); + grid.set_tile(1, 5, Tile::from(TileType::Wall)); + grid.set_tile(2, 5, Tile::from(TileType::Floor)); + grid.set_tile(3, 5, Tile::from(TileType::Floor)); + + grid.clear_los(&(3, 5), &(0, 5)); + assert_eq!(grid.tile_at(4, 5).is_visible(), false); + assert_eq!(grid.tile_at(3, 5).is_visible(), true); + assert_eq!(grid.tile_at(2, 4).is_visible(), false); + assert_eq!(grid.tile_at(2, 5).is_visible(), true); + assert_eq!(grid.tile_at(2, 6).is_visible(), false); + assert_eq!(grid.tile_at(1, 5).is_visible(), true); + assert_eq!(grid.tile_at(0, 6).is_visible(), false); + } +} -- cgit v1.2.3 From 7074a8c0075fd89f1d6a8376025b292702aac9f3 Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Mon, 9 Mar 2020 21:55:45 +0000 Subject: Fix LOS --- src/tiling.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tiling.rs b/src/tiling.rs index a48d57e..c121eb4 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -130,10 +130,6 @@ impl TileGrid { self.reveal(start.0, start.1); loop { - if let TileType::Empty = self.tile_at(x, y).get_type() { - break; - } - if x == end.0 && y == end.1 { // self.reveal(x, y); break; @@ -148,6 +144,11 @@ impl TileGrid { err += dx; y = (y as isize + sy).max(0) as usize; } + + if let TileType::Empty = self.tile_at(x, y).get_type() { + break; + } + self.reveal(x, y); } } -- cgit v1.2.3 From 859a0645114b0d58c2ba8476e9900a74443da70c Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Mon, 9 Mar 2020 23:06:03 +0000 Subject: Handle opacity better, use roundish view radius --- src/entities.rs | 1 + src/tiling.rs | 154 +++++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 110 insertions(+), 45 deletions(-) diff --git a/src/entities.rs b/src/entities.rs index 430e37a..78e5ab9 100644 --- a/src/entities.rs +++ b/src/entities.rs @@ -179,6 +179,7 @@ impl Player for Character { tile: Tile::new( TileType::Player, true, // player is visible by default + false, ), dirty: false, visible: true, diff --git a/src/tiling.rs b/src/tiling.rs index c121eb4..6719715 100644 --- a/src/tiling.rs +++ b/src/tiling.rs @@ -1,7 +1,7 @@ use log::debug; use std::convert::From; -#[derive(Clone, Debug)] +#[derive(Copy, Clone, Debug)] pub enum TileType { Empty, Wall, @@ -16,11 +16,16 @@ pub enum TileType { pub struct Tile { tile_type: TileType, visible: bool, + opaque: bool, } impl Tile { - pub fn new(tile_type: TileType, visible: bool) -> Self { - Tile { tile_type, visible } + pub fn new(tile_type: TileType, visible: bool, opaque: bool) -> Self { + Tile { + tile_type, + visible, + opaque, + } } pub fn get_type(&self) -> &TileType { @@ -34,6 +39,14 @@ impl Tile { pub fn visibility(&mut self, visible: bool) { self.visible = visible; } + + pub fn is_opaque(&self) -> bool { + self.opaque + } + + pub fn opacity(&mut self, opaque: bool) { + self.opaque = opaque + } } impl From for Tile { @@ -41,8 +54,13 @@ impl From for Tile { Tile { tile_type, visible: false, // <--- TODO: this set the default beaviour - // - true: all tiles of world and entities will be drawn - // - false: only draw tiles visible for the player + // - true: all tiles of world and entities will be drawn + // - false: only draw tiles visible for the player + opaque: match tile_type { + TileType::Empty => true, + TileType::Wall => true, + _ => false, + }, } } } @@ -64,7 +82,7 @@ impl TileGrid { for _ in 0..ysize { let mut subvec = Vec::with_capacity(xsize); for _ in 0..xsize { - subvec.push(Tile::new(TileType::Empty, false)); + subvec.push(Tile::from(TileType::Empty)); } grid.grid.push(subvec); } @@ -129,12 +147,7 @@ impl TileGrid { // the tile we're standing on needs to be visible. self.reveal(start.0, start.1); - loop { - if x == end.0 && y == end.1 { - // self.reveal(x, y); - break; - } - + while x != end.0 && y != end.1 { let err2 = 2 * err; if err2 >= dy { err += dy; @@ -145,46 +158,24 @@ impl TileGrid { y = (y as isize + sy).max(0) as usize; } - if let TileType::Empty = self.tile_at(x, y).get_type() { + self.reveal(x, y); + + if self.tile_at(x, y).is_opaque() { break; } - - self.reveal(x, y); } } /// 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); - - debug!("LOS: {:?} - {:?} {:?} {:?} {:?}", center, a, b, c, d); - - // From a to b - for x in a.0..=b.0 { - // debug!("Clear LOS from {:?} to {:?}", center, (x, a.1)); - self.clear_los(center, &(x, a.1)); - } - // From b to c - for y in b.1..=c.1 { - // debug!("Clear LOS from {:?} to {:?}", center, (b.0, y)); - self.clear_los(center, &(b.0, y)); - } - // From c to d - for x in d.0..=c.0 { - // debug!("Clear LOS from {:?} to {:?}", center, (x, c.1)); - self.clear_los(center, &(x, c.1)); - } - // From d to a - for y in a.1..=d.1 { - // debug!("Clear LOS from {:?} to {:?}", center, (d.0, y)); - self.clear_los(center, &(d.0, y)); + let perimeter = circle(&(center.0, center.1 + 1), radius); + + for point in perimeter.iter() { + self.clear_los( + center, + &(point.0.min(self.xsize), point.1.min(self.ysize())), + ); } } } @@ -209,6 +200,43 @@ pub trait Tileable { fn tile(&self, grid: &mut TileGrid) -> Result<(), String>; } +fn circle(center: &(usize, usize), radius: usize) -> Vec<(usize, usize)> { + let mut x: i32 = radius as i32; + let mut y: i32 = 0; + let mut err: i32 = 0; + + let signs: [i32; 2] = [-1, 1]; + let mut points: Vec<(usize, usize)> = vec![]; + + while x >= y { + for xsign in signs.iter() { + for ysign in signs.iter() { + points.push(( + (center.0 as i32 + xsign * x).max(0) as usize, + (center.1 as i32 + ysign * y).max(0) as usize, + )); + points.push(( + (center.0 as i32 + xsign * y).max(0) as usize, + (center.1 as i32 + ysign * x).max(0) as usize, + )); + } + } + + if err <= 0 { + y += 1; + err += 2 * y + 1; + } + + if err > 0 { + x -= 1; + err -= 2 * x + 1; + } + } + points.sort(); + points.dedup(); + points +} + #[cfg(test)] mod tests { use super::*; @@ -230,7 +258,7 @@ mod tests { #[test] fn tiles_can_be_revealed() { - let mut tile = Tile::new(TileType::Wall, false); + let mut tile = Tile::from(TileType::Wall); assert_eq!(tile.visible, false); assert_eq!(tile.is_visible(), false); tile.visibility(true); @@ -263,6 +291,20 @@ mod tests { assert_eq!(grid.tile_at(5, 0).is_visible(), false); } + #[test] + fn test_clear_los_stops_at_contiguous_wall_up() { + let mut grid = TileGrid::new(9, 9); + grid.set_tile(5, 1, Tile::from(TileType::Floor)); + grid.set_tile(5, 2, Tile::from(TileType::Wall)); + grid.set_tile(5, 3, Tile::from(TileType::Floor)); + + grid.clear_los(&(5, 3), &(5, 0)); + assert_eq!(grid.tile_at(5, 0).is_visible(), false); + assert_eq!(grid.tile_at(5, 1).is_visible(), false); + assert_eq!(grid.tile_at(5, 2).is_visible(), true); + assert_eq!(grid.tile_at(5, 3).is_visible(), true); + } + #[test] fn test_clear_los_clears_to_wall_on_vertical_down() { let mut grid = TileGrid::new(9, 9); @@ -313,4 +355,26 @@ mod tests { assert_eq!(grid.tile_at(1, 5).is_visible(), true); assert_eq!(grid.tile_at(0, 6).is_visible(), false); } + + #[test] + fn circle_creates_a_circle() { + let circ = circle(&(10, 10), 3); + assert_eq!( + circ.as_slice(), + [ + (7, 10), + (8, 9), + (8, 11), + (9, 8), + (9, 12), + (10, 7), + (10, 13), + (11, 8), + (11, 12), + (12, 9), + (12, 11), + (13, 10) + ] + ) + } } -- cgit v1.2.3 From 0191b3a881027bcb6d6210e010841664dae4204b Mon Sep 17 00:00:00 2001 From: Guillaume Pasquet Date: Tue, 10 Mar 2020 08:53:55 +0000 Subject: More to do --- TODO.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TODO.md b/TODO.md index ed27c7c..9289b2d 100644 --- a/TODO.md +++ b/TODO.md @@ -1,4 +1,4 @@ - Add unit tests -- Add walls collision support -- Add basic entity interactions (staircases etc.) +- Disassociate level to view, move view around if terminal too small - Add equipment system +- Remove rendering logic from State \ No newline at end of file -- cgit v1.2.3