From bafe3fcbc9af6a5c9f93e85832e24ce3a0f95a59 Mon Sep 17 00:00:00 2001 From: Peter Hart Date: Sun, 29 Mar 2020 15:48:52 -0400 Subject: [PATCH] handling visibility, also fixed corridor issue --- src/main.rs | 42 +++++++++++++++++++++++++-- src/map.rs | 61 +++++++++++++--------------------------- src/visibility_system.rs | 35 +++++++++++++++++++---- 3 files changed, 89 insertions(+), 49 deletions(-) diff --git a/src/main.rs b/src/main.rs index b8461e9..c15774e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -67,8 +67,7 @@ impl GameState for State { ctx.cls(); self.run_systems(); player_input(self, ctx); - let map = self.ecs.fetch::(); - map.draw_map(ctx); + draw_map(&self.ecs, ctx); let positions = self.ecs.read_storage::(); let renderables = self.ecs.read_storage::(); @@ -78,6 +77,45 @@ impl GameState for State { } } +pub fn draw_map(ecs: &World, ctx: &mut Rltk) { + let map = ecs.fetch::(); + + let mut y = 0; + let mut x = 0; + for (idx, tile) in map.tiles.iter().enumerate() { + // Render a tile depending upon the tile type, if revealed + if map.revealed_tiles[idx] { + match tile { + TileType::Floor => { + ctx.set( + x, + y, + RGB::from_f32(0.5, 0.5, 0.5), + RGB::from_f32(0., 0., 0.), + rltk::to_cp437('.'), + ); + } + TileType::Wall => { + ctx.set( + x, + y, + RGB::from_f32(0.0, 1.0, 0.0), + RGB::from_f32(0., 0., 0.), + rltk::to_cp437('#'), + ); + } + } + } + + // Move the coordinates + x += 1; + if x >= map.width { + x = 0; + y += 1; + } + } +} + fn main() { use rltk::RltkBuilder; let context = RltkBuilder::simple80x50() diff --git a/src/map.rs b/src/map.rs index 391426b..5f92245 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,5 +1,5 @@ use super::rect::*; -use rltk::{Console, RandomNumberGenerator, Rltk, RGB}; +use rltk::{Algorithm2D, BaseMap, Point, RandomNumberGenerator}; use std::cmp::{max, min}; #[derive(PartialEq, Copy, Clone)] @@ -7,12 +7,13 @@ pub enum TileType { Wall, Floor, } - +#[derive(Default)] pub struct Map { pub tiles: Vec, pub rooms: Vec, pub width: i32, pub height: i32, + pub revealed_tiles: Vec, } impl Map { @@ -20,14 +21,14 @@ impl Map { ((y * self.width) + x) as usize } - pub fn tile_at(&self, x: i32, y:i32) -> TileType { + pub fn tile_at(&self, x: i32, y: i32) -> TileType { self.tiles[self.xy_idx(x, y)] } fn apply_room_to_map(&mut self, room: &Rect) { for x in room.x1..room.x2 { for y in room.y1..room.y2 { - let idx = self.xy_idx(x,y); + let idx = self.xy_idx(x, y); self.tiles[idx] = TileType::Floor } } @@ -35,14 +36,14 @@ impl Map { fn apply_horizontal_tunnel(&mut self, x1: i32, x2: i32, y: i32) { for x in min(x1, x2)..=max(x1, x2) { - let idx=self.xy_idx(x, y); + let idx = self.xy_idx(x, y); self.tiles[idx] = TileType::Floor } } fn apply_vertical_tunnel(&mut self, x: i32, y1: i32, y2: i32) { for y in min(y1, y2)..=max(y1, y2) { - let idx=self.xy_idx(x, y); + let idx = self.xy_idx(x, y); self.tiles[idx] = TileType::Floor } } @@ -53,6 +54,7 @@ impl Map { rooms: Vec::new(), width: 80, height: 50, + revealed_tiles: vec![false; 80 * 50], }; const MAX_ROOMS: i32 = 30; @@ -81,7 +83,7 @@ impl Map { if rng.range(0, 2) == 1 { map.apply_horizontal_tunnel(r1_center.0, r2_center.0, r1_center.1); map.apply_vertical_tunnel( - max(r1_center.0, r2_center.0), + r2_center.0, r1_center.1, r2_center.1, ); @@ -90,7 +92,7 @@ impl Map { map.apply_horizontal_tunnel( r1_center.0, r2_center.0, - max(r1_center.1, r2_center.1), + r2_center.1, ); } } @@ -100,39 +102,16 @@ impl Map { map } +} - pub fn draw_map(&self, ctx: &mut Rltk) { - let mut y = 0; - let mut x = 0; - for tile in self.tiles.iter() { - // Render a tile depending upon the tile type - match tile { - TileType::Floor => { - ctx.set( - x, - y, - RGB::from_f32(0.5, 0.5, 0.5), - RGB::from_f32(0., 0., 0.), - rltk::to_cp437('.'), - ); - } - TileType::Wall => { - ctx.set( - x, - y, - RGB::from_f32(0.0, 1.0, 0.0), - RGB::from_f32(0., 0., 0.), - rltk::to_cp437('#'), - ); - } - } - - // Move the coordinates - x += 1; - if x > 79 { - x = 0; - y += 1; - } - } +impl BaseMap for Map { + fn is_opaque(&self, idx: usize) -> bool { + self.tiles[idx as usize] == TileType::Wall + } +} + +impl Algorithm2D for Map { + fn dimensions(&self) -> Point { + Point::new(self.width, self.height) } } diff --git a/src/visibility_system.rs b/src/visibility_system.rs index c568930..47bfc68 100644 --- a/src/visibility_system.rs +++ b/src/visibility_system.rs @@ -1,15 +1,38 @@ extern crate specs; +use super::{Map, Player, Position, Viewshed}; use specs::prelude::*; -use super::{Viewshed, Position}; +extern crate rltk; +use rltk::{field_of_view, Point}; pub struct VisibilitySystem {} impl<'a> System<'a> for VisibilitySystem { - type SystemData = ( WriteStorage<'a, Viewshed>, - WriteStorage<'a, Position>); + type SystemData = ( + WriteExpect<'a, Map>, + Entities<'a>, + WriteStorage<'a, Viewshed>, + WriteStorage<'a, Position>, + ReadStorage<'a, Player>, + ); - fn run(&mut self, (mut viewshed, pos) : Self::SystemData) { - for (viewshed,pos) in (&mut viewshed, &pos).join() { + fn run(&mut self, data: Self::SystemData) { + let (mut map, entities, mut viewshed, pos, player) = data; + + for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() { + viewshed.visible_tiles.clear(); + viewshed.visible_tiles = field_of_view(Point::new(pos.x, pos.y), viewshed.range, &*map); + viewshed + .visible_tiles + .retain(|p| p.x > 0 && p.x < map.width - 1 && p.y > 0 && p.y < map.height - 1); + + // If this is the player, reveal what they can see + let p: Option<&Player> = player.get(ent); + if let Some(p) = p { + for vis in viewshed.visible_tiles.iter() { + let idx = map.xy_idx(vis.x, vis.y); + map.revealed_tiles[idx] = true; + } + } } } -} \ No newline at end of file +}