Squashed commit of the following:
commit dc60721a63edc97256be2d1d16b03ca2497e6338 Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Sat Jul 10 00:00:58 2021 -0500 Add dimmed revealed map tiles commit 22379f785c82951e90d8161fcb151e8597ba039e Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:42:56 2021 -0500 Only chase player if the monster can see them commit 9b830471da5bafdfef6b62f2963a6b2376b6f660 Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:39:27 2021 -0500 Recalculate player fov on move commit e6327c704b7f60062d08496788c1cce55aee6e2b Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:38:37 2021 -0500 Only render tooltips in the players fov commit 1d9d1b9a6216cd29768366eedd4499c1a4e6dc4a Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:38:21 2021 -0500 Only render entities in player fov commit 339a8dfcfe875687fb6a5db6873a6c3a31acab5d Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:37:50 2021 -0500 Only render map tiles in the player's fov commit 81a6789d5924a9e36f474406399d42b4821cfa76 Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:37:21 2021 -0500 Add fov component to player and monsters commit fecbd30b6380e951678aa73b03188d9a0dfaeb40 Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:37:05 2021 -0500 Designate opaque tiles commit 1bcdcfd8f8b87a03ad89f155130bf2e6d1c9200d Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:36:43 2021 -0500 Add fov system commit b9314af566ed28ceec97724334fabe248004466e Author: Daniel Lynn <daniel.eric.lynn@gmail.com> Date: Fri Jul 9 23:36:17 2021 -0500 Add FieldOfView component
This commit is contained in:
parent
3f9d567d8b
commit
9cd0af9679
@ -1,4 +1,5 @@
|
||||
use crate::prelude::*;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct Render {
|
||||
@ -44,3 +45,28 @@ pub struct Item;
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct AmuletOfYala;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct FieldOfView {
|
||||
pub visible_tiles: HashSet<Point>,
|
||||
pub radius: i32,
|
||||
pub is_dirty: bool,
|
||||
}
|
||||
|
||||
impl FieldOfView {
|
||||
pub fn new(radius: i32) -> Self {
|
||||
Self {
|
||||
visible_tiles: HashSet::new(),
|
||||
radius,
|
||||
is_dirty: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clone_dirty(&self) -> Self {
|
||||
Self {
|
||||
visible_tiles: HashSet::new(),
|
||||
radius: self.radius,
|
||||
is_dirty: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ pub enum TileType {
|
||||
|
||||
pub struct Map {
|
||||
pub tiles: Vec<TileType>,
|
||||
pub revealed_tiles: Vec<bool>,
|
||||
}
|
||||
|
||||
pub fn map_idx(x: i32, y: i32) -> usize {
|
||||
@ -20,6 +21,7 @@ impl Map {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tiles: vec![TileType::Floor; NUM_TILES],
|
||||
revealed_tiles: vec![false; NUM_TILES],
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,4 +86,8 @@ impl BaseMap for Map {
|
||||
fn get_pathing_distance(&self, idx1: usize, idx2: usize) -> f32 {
|
||||
DistanceAlg::Pythagoras.distance2d(self.index_to_point2d(idx1), self.index_to_point2d(idx2))
|
||||
}
|
||||
|
||||
fn is_opaque(&self, idx: usize) -> bool {
|
||||
self.tiles[idx as usize] != TileType::Floor
|
||||
}
|
||||
}
|
||||
|
@ -13,6 +13,7 @@ pub fn spawn_player(ecs: &mut World, pos: Point) {
|
||||
max: 10,
|
||||
},
|
||||
Name("Player 1".to_string()),
|
||||
FieldOfView::new(8),
|
||||
));
|
||||
}
|
||||
|
||||
@ -35,6 +36,7 @@ pub fn spawn_monster(ecs: &mut World, rng: &mut RandomNumberGenerator, pos: Poin
|
||||
max: hp,
|
||||
},
|
||||
Name(name),
|
||||
FieldOfView::new(6),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -5,8 +5,9 @@ use crate::prelude::*;
|
||||
#[read_component(ChasingPlayer)]
|
||||
#[read_component(Health)]
|
||||
#[read_component(Player)]
|
||||
#[read_component(FieldOfView)]
|
||||
pub fn chasing(#[resource] map: &Map, ecs: &SubWorld, commands: &mut CommandBuffer) {
|
||||
let mut movers = <(Entity, &Point, &ChasingPlayer)>::query();
|
||||
let mut movers = <(Entity, &Point, &ChasingPlayer, &FieldOfView)>::query();
|
||||
let mut positions = <(Entity, &Point, &Health)>::query();
|
||||
let mut player = <(&Point, &Player)>::query();
|
||||
let player_pos = player.iter(ecs).next().unwrap().0;
|
||||
@ -14,7 +15,10 @@ pub fn chasing(#[resource] map: &Map, ecs: &SubWorld, commands: &mut CommandBuff
|
||||
let search_targets = vec![player_idx];
|
||||
let dijkstra_map = DijkstraMap::new(SCREEN_WIDTH, SCREEN_HEIGHT, &search_targets, map, 1024.0);
|
||||
|
||||
movers.iter(ecs).for_each(|(entity, pos, _)| {
|
||||
movers.iter(ecs).for_each(|(entity, pos, _, fov)| {
|
||||
if !fov.visible_tiles.contains(&player_pos) {
|
||||
return;
|
||||
}
|
||||
let idx = map_idx(pos.x, pos.y);
|
||||
if let Some(destination) = DijkstraMap::find_lowest_exit(&dijkstra_map, idx, map) {
|
||||
let distance = DistanceAlg::Pythagoras.distance2d(*pos, *player_pos);
|
||||
|
@ -3,13 +3,19 @@ use crate::prelude::*;
|
||||
#[system]
|
||||
#[read_component(Point)]
|
||||
#[read_component(Render)]
|
||||
#[read_component(FieldOfView)]
|
||||
#[read_component(Player)]
|
||||
pub fn entity_render(ecs: &SubWorld, #[resource] camera: &Camera) {
|
||||
let mut renderables = <(&Point, &Render)>::query();
|
||||
let mut fov = <&FieldOfView>::query().filter(component::<Player>());
|
||||
let player_fov = fov.iter(ecs).next().unwrap();
|
||||
let mut draw_batch = DrawBatch::new();
|
||||
let offset = Point::new(camera.left_x, camera.top_y);
|
||||
|
||||
draw_batch.target(1);
|
||||
<(&Point, &Render)>::query()
|
||||
renderables
|
||||
.iter(ecs)
|
||||
.filter(|(pos, _)| player_fov.visible_tiles.contains(&pos))
|
||||
.for_each(|(pos, render)| {
|
||||
draw_batch.set(*pos - offset, render.color, render.glyph);
|
||||
});
|
||||
|
15
src/systems/fov.rs
Normal file
15
src/systems/fov.rs
Normal file
@ -0,0 +1,15 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[system]
|
||||
#[read_component(Point)]
|
||||
#[write_component(FieldOfView)]
|
||||
pub fn fov(ecs: &mut SubWorld, #[resource] map: &Map) {
|
||||
let mut views = <(&Point, &mut FieldOfView)>::query();
|
||||
views
|
||||
.iter_mut(ecs)
|
||||
.filter(|(_, fov)| fov.is_dirty)
|
||||
.for_each(|(pos, mut fov)| {
|
||||
fov.visible_tiles = field_of_view_set(*pos, fov.radius, map);
|
||||
fov.is_dirty = false;
|
||||
});
|
||||
}
|
@ -1,20 +1,38 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
#[system]
|
||||
pub fn map_render(#[resource] map: &Map, #[resource] camera: &Camera) {
|
||||
#[read_component(FieldOfView)]
|
||||
#[read_component(Player)]
|
||||
pub fn map_render(ecs: &SubWorld, #[resource] map: &Map, #[resource] camera: &Camera) {
|
||||
let mut fov = <&FieldOfView>::query().filter(component::<Player>());
|
||||
let player_fov = fov.iter(ecs).next().unwrap();
|
||||
let mut draw_batch = DrawBatch::new();
|
||||
|
||||
draw_batch.target(0);
|
||||
|
||||
for y in camera.top_y..=camera.bottom_y {
|
||||
for x in camera.left_x..=camera.right_x {
|
||||
let pt = Point::new(x, y);
|
||||
let offset = Point::new(camera.left_x, camera.top_y);
|
||||
if map.in_bounds(pt) {
|
||||
let idx = map_idx(x, y);
|
||||
let glyph = match map.tiles[idx] {
|
||||
TileType::Floor => to_cp437('.'),
|
||||
TileType::Wall => to_cp437('#'),
|
||||
let idx = map_idx(x, y);
|
||||
|
||||
if map.in_bounds(pt)
|
||||
&& (player_fov.visible_tiles.contains(&pt) | map.revealed_tiles[idx])
|
||||
{
|
||||
let tint = if player_fov.visible_tiles.contains(&pt) {
|
||||
WHITE
|
||||
} else {
|
||||
DARK_GRAY
|
||||
};
|
||||
|
||||
match map.tiles[idx] {
|
||||
TileType::Floor => {
|
||||
draw_batch.set(pt - offset, ColorPair::new(tint, BLACK), to_cp437('.'))
|
||||
}
|
||||
TileType::Wall => {
|
||||
draw_batch.set(pt - offset, ColorPair::new(tint, BLACK), to_cp437('#'))
|
||||
}
|
||||
};
|
||||
draw_batch.set(pt - offset, ColorPair::new(WHITE, BLACK), glyph);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ mod chasing;
|
||||
mod combat;
|
||||
mod end_turn;
|
||||
mod entity_render;
|
||||
mod fov;
|
||||
mod hud;
|
||||
mod map_render;
|
||||
mod movement;
|
||||
@ -14,6 +15,7 @@ use crate::prelude::*;
|
||||
pub fn build_input_scheduler() -> Schedule {
|
||||
Schedule::builder()
|
||||
.add_system(player_input::player_input_system())
|
||||
.add_system(fov::fov_system())
|
||||
.flush()
|
||||
.add_system(map_render::map_render_system())
|
||||
.add_system(entity_render::entity_render_system())
|
||||
@ -28,6 +30,8 @@ pub fn build_player_scheduler() -> Schedule {
|
||||
.flush()
|
||||
.add_system(movement::movement_system())
|
||||
.flush()
|
||||
.add_system(fov::fov_system())
|
||||
.flush()
|
||||
.add_system(map_render::map_render_system())
|
||||
.add_system(entity_render::entity_render_system())
|
||||
.add_system(hud::hud_system())
|
||||
@ -45,6 +49,8 @@ pub fn build_monster_scheduler() -> Schedule {
|
||||
.flush()
|
||||
.add_system(movement::movement_system())
|
||||
.flush()
|
||||
.add_system(fov::fov_system())
|
||||
.flush()
|
||||
.add_system(map_render::map_render_system())
|
||||
.add_system(entity_render::entity_render_system())
|
||||
.add_system(hud::hud_system())
|
||||
|
@ -2,10 +2,11 @@ use crate::prelude::*;
|
||||
|
||||
#[system(for_each)]
|
||||
#[read_component(Player)]
|
||||
#[read_component(FieldOfView)]
|
||||
pub fn movement(
|
||||
entity: &Entity,
|
||||
want_move: &WantsToMove,
|
||||
#[resource] map: &Map,
|
||||
#[resource] map: &mut Map,
|
||||
#[resource] camera: &mut Camera,
|
||||
ecs: &mut SubWorld,
|
||||
commands: &mut CommandBuffer,
|
||||
@ -13,14 +14,20 @@ pub fn movement(
|
||||
if map.can_enter_tile(want_move.destination) {
|
||||
commands.add_component(want_move.entity, want_move.destination);
|
||||
|
||||
if ecs
|
||||
.entry_ref(want_move.entity)
|
||||
.unwrap()
|
||||
.get_component::<Player>()
|
||||
.is_ok()
|
||||
{
|
||||
camera.on_player_move(want_move.destination)
|
||||
if let Ok(entry) = ecs.entry_ref(want_move.entity) {
|
||||
if let Ok(fov) = entry.get_component::<FieldOfView>() {
|
||||
commands.add_component(want_move.entity, fov.clone_dirty());
|
||||
|
||||
if entry.get_component::<Player>().is_ok() {
|
||||
camera.on_player_move(want_move.destination);
|
||||
|
||||
fov.visible_tiles.iter().for_each(|pos| {
|
||||
map.revealed_tiles[map_idx(pos.x, pos.y)] = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
commands.remove(*entity);
|
||||
}
|
||||
|
@ -4,15 +4,19 @@ use crate::prelude::*;
|
||||
#[read_component(Point)]
|
||||
#[read_component(Name)]
|
||||
#[read_component(Health)]
|
||||
#[read_component(FieldOfView)]
|
||||
#[read_component(Player)]
|
||||
pub fn tooltips(ecs: &SubWorld, #[resource] mouse_pos: &Point, #[resource] camera: &Camera) {
|
||||
let mut positions = <(Entity, &Point, &Name)>::query();
|
||||
let mut fov = <&FieldOfView>::query().filter(component::<Player>());
|
||||
let player_fov = fov.iter(ecs).next().unwrap();
|
||||
let offset = Point::new(camera.left_x, camera.top_y);
|
||||
let map_pos = *mouse_pos + offset;
|
||||
let mut draw_batch = DrawBatch::new();
|
||||
draw_batch.target(2);
|
||||
positions
|
||||
.iter(ecs)
|
||||
.filter(|(_, pos, _)| **pos == map_pos)
|
||||
.filter(|(_, pos, _)| **pos == map_pos && player_fov.visible_tiles.contains(&pos))
|
||||
.for_each(|(entity, _, name)| {
|
||||
let screen_pos = *mouse_pos * 4;
|
||||
let display =
|
||||
|
Loading…
x
Reference in New Issue
Block a user