map memory
This commit is contained in:
parent
054468bbae
commit
cfbe4098b7
3 changed files with 86 additions and 60 deletions
96
src/main.rs
96
src/main.rs
|
|
@ -154,7 +154,6 @@ const SHOW_BOUNDARIES: bool = false; // Config setting
|
||||||
enum DrawType {
|
enum DrawType {
|
||||||
None,
|
None,
|
||||||
Visible,
|
Visible,
|
||||||
VisibleAndRemember,
|
|
||||||
Telepathy,
|
Telepathy,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,12 +169,12 @@ struct DrawInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_camera(
|
fn draw_camera(
|
||||||
|
map: &Map,
|
||||||
ecs: &World,
|
ecs: &World,
|
||||||
draw: &mut Draw,
|
draw: &mut Draw,
|
||||||
atlas: &HashMap<String, Texture>,
|
atlas: &HashMap<String, Texture>,
|
||||||
font: ¬an::draw::Font
|
font: ¬an::draw::Font
|
||||||
) {
|
) {
|
||||||
let map = ecs.fetch::<Map>();
|
|
||||||
render_map_in_view(&*map, ecs, draw, atlas, false);
|
render_map_in_view(&*map, ecs, draw, atlas, false);
|
||||||
{
|
{
|
||||||
let bounds = crate::camera::get_screen_bounds(ecs, false);
|
let bounds = crate::camera::get_screen_bounds(ecs, false);
|
||||||
|
|
@ -204,17 +203,8 @@ fn draw_camera(
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
let draw_type = if map.visible_tiles[idx] {
|
let draw_type = if map.visible_tiles[idx] {
|
||||||
let is_prop = props.get(*e);
|
// If it's anything else, just draw it.
|
||||||
let is_item = items.get(*e);
|
DrawType::Visible
|
||||||
if is_prop.is_some() || is_item.is_some() {
|
|
||||||
// If it's a static entity, we want to draw it, and
|
|
||||||
// also save it's location so that we remember where
|
|
||||||
// it was last seen after it leaves vision.
|
|
||||||
DrawType::VisibleAndRemember
|
|
||||||
} else {
|
|
||||||
// If it's anything else, just draw it.
|
|
||||||
DrawType::Visible
|
|
||||||
}
|
|
||||||
} else if map.telepath_tiles[idx] {
|
} else if map.telepath_tiles[idx] {
|
||||||
let has_mind = minds.get(*e);
|
let has_mind = minds.get(*e);
|
||||||
if has_mind.is_some() {
|
if has_mind.is_some() {
|
||||||
|
|
@ -317,50 +307,6 @@ fn draw_camera(
|
||||||
.v_align_middle();
|
.v_align_middle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DrawType::VisibleAndRemember => {
|
|
||||||
// TODO: PUT THIS INTO A FUNCTION!
|
|
||||||
let renderable = renderables.get(entry.1.e).unwrap();
|
|
||||||
if let Some(spriteinfo) = &renderable.sprite {
|
|
||||||
let id = if let Some(sprite) = atlas.get(&spriteinfo.id) {
|
|
||||||
sprite
|
|
||||||
} else {
|
|
||||||
panic!("No entity sprite found for ID: {}", spriteinfo.id);
|
|
||||||
};
|
|
||||||
draw.image(id)
|
|
||||||
.position(
|
|
||||||
((entry.0.x as f32) + spriteinfo.offset.0) * TILESIZE,
|
|
||||||
((entry.0.y as f32) + spriteinfo.offset.1) * TILESIZE
|
|
||||||
)
|
|
||||||
.color(
|
|
||||||
if spriteinfo.recolour {
|
|
||||||
Color::from_rgb(
|
|
||||||
renderable.fg.r,
|
|
||||||
renderable.fg.g,
|
|
||||||
renderable.fg.b
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Color::WHITE
|
|
||||||
}
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Fallback to drawing text.
|
|
||||||
draw.text(
|
|
||||||
&font,
|
|
||||||
&format!("{}", bracket_lib::terminal::to_char(renderable.glyph as u8))
|
|
||||||
)
|
|
||||||
.position(
|
|
||||||
((entry.0.x as f32) + 0.5) * TILESIZE,
|
|
||||||
((entry.0.y as f32) + 0.5) * TILESIZE
|
|
||||||
)
|
|
||||||
.color(
|
|
||||||
Color::from_rgb(renderable.fg.r, renderable.fg.g, renderable.fg.b)
|
|
||||||
)
|
|
||||||
.size(FONTSIZE)
|
|
||||||
.h_align_center()
|
|
||||||
.v_align_middle();
|
|
||||||
}
|
|
||||||
// TODO: Update map memory.
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -408,6 +354,34 @@ fn render_map_in_view(
|
||||||
)
|
)
|
||||||
.color(tint);
|
.color(tint);
|
||||||
}
|
}
|
||||||
|
if !map.visible_tiles[idx] {
|
||||||
|
// Recall map memory. TODO: Improve this? Optimize? Do we need to remember more fields?
|
||||||
|
if let Some(memories) = map.memory.get(&idx) {
|
||||||
|
let mut sorted: Vec<_> = memories.iter().collect();
|
||||||
|
sorted.sort_by(|a, b| a.render_order.cmp(&b.render_order));
|
||||||
|
for memory in sorted.iter() {
|
||||||
|
let sprite = if let Some(sprite) = atlas.get(&memory.sprite) {
|
||||||
|
sprite
|
||||||
|
} else {
|
||||||
|
panic!("No sprite found for ID: {}", memory.sprite);
|
||||||
|
};
|
||||||
|
draw.image(sprite)
|
||||||
|
.position(
|
||||||
|
(((x + bounds.x_offset) as f32) + memory.offset.0) *
|
||||||
|
TILESIZE,
|
||||||
|
(((y + bounds.y_offset) as f32) + memory.offset.1) *
|
||||||
|
TILESIZE
|
||||||
|
)
|
||||||
|
.color(
|
||||||
|
if memory.recolour {
|
||||||
|
Color::from_rgb(memory.fg.r, memory.fg.g, memory.fg.b)
|
||||||
|
} else {
|
||||||
|
Color::from_rgb(0.75, 0.75, 0.75)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if SHOW_BOUNDARIES {
|
} else if SHOW_BOUNDARIES {
|
||||||
// TODO: Draw boundaries
|
// TODO: Draw boundaries
|
||||||
|
|
@ -524,7 +498,8 @@ fn draw(_app: &mut App, gfx: &mut Graphics, gs: &mut State) {
|
||||||
let mut draw = gfx.create_draw();
|
let mut draw = gfx.create_draw();
|
||||||
draw.clear(Color::BLACK);
|
draw.clear(Color::BLACK);
|
||||||
let mut log = false;
|
let mut log = false;
|
||||||
match *gs.ecs.fetch::<RunState>() {
|
let runstate = *gs.ecs.fetch::<RunState>();
|
||||||
|
match runstate {
|
||||||
| RunState::MainMenu { .. }
|
| RunState::MainMenu { .. }
|
||||||
| RunState::CharacterCreation { .. }
|
| RunState::CharacterCreation { .. }
|
||||||
| RunState::PreRun { .. } => {}
|
| RunState::PreRun { .. } => {}
|
||||||
|
|
@ -541,13 +516,14 @@ fn draw(_app: &mut App, gfx: &mut Graphics, gs: &mut State) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
let map = gs.ecs.fetch::<Map>();
|
||||||
draw_bg(&gs.ecs, &mut draw, &gs.atlas);
|
draw_bg(&gs.ecs, &mut draw, &gs.atlas);
|
||||||
draw_camera(&gs.ecs, &mut draw, &gs.atlas, &gs.font);
|
draw_camera(&*map, &gs.ecs, &mut draw, &gs.atlas, &gs.font);
|
||||||
gui::draw_ui2(&gs.ecs, &mut draw, &gs.atlas, &gs.font);
|
gui::draw_ui2(&gs.ecs, &mut draw, &gs.atlas, &gs.font);
|
||||||
log = true;
|
log = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
match *gs.ecs.fetch::<RunState>() {
|
match runstate {
|
||||||
RunState::Farlook { x, y } => {
|
RunState::Farlook { x, y } => {
|
||||||
gui::draw_farlook(x, y, &mut draw, &gs.atlas);
|
gui::draw_farlook(x, y, &mut draw, &gs.atlas);
|
||||||
//draw_tooltips(&gs.ecs, ctx, Some((x, y))); TODO: Put this in draw loop
|
//draw_tooltips(&gs.ecs, ctx, Some((x, y))); TODO: Put this in draw loop
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,15 @@ use super::consts::visuals::{
|
||||||
// i.e. on a map size of 40*40, only entities to the left of the player are rendered.
|
// i.e. on a map size of 40*40, only entities to the left of the player are rendered.
|
||||||
// on a map size of 42*42, the player can see entities up to 2 tiles to their right.
|
// on a map size of 42*42, the player can see entities up to 2 tiles to their right.
|
||||||
|
|
||||||
|
#[derive(Clone, Serialize, Deserialize)]
|
||||||
|
pub struct MapMemory {
|
||||||
|
pub sprite: String,
|
||||||
|
pub fg: RGB,
|
||||||
|
pub recolour: bool,
|
||||||
|
pub offset: (f32, f32),
|
||||||
|
pub render_order: i32,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Serialize, Deserialize, Clone)]
|
#[derive(Default, Serialize, Deserialize, Clone)]
|
||||||
pub struct Map {
|
pub struct Map {
|
||||||
pub overmap: bool,
|
pub overmap: bool,
|
||||||
|
|
@ -33,6 +42,7 @@ pub struct Map {
|
||||||
pub width: i32,
|
pub width: i32,
|
||||||
pub height: i32,
|
pub height: i32,
|
||||||
pub revealed_tiles: Vec<bool>,
|
pub revealed_tiles: Vec<bool>,
|
||||||
|
pub memory: HashMap<usize, Vec<MapMemory>>,
|
||||||
pub visible_tiles: Vec<bool>,
|
pub visible_tiles: Vec<bool>,
|
||||||
pub lit_tiles: Vec<bool>,
|
pub lit_tiles: Vec<bool>,
|
||||||
pub telepath_tiles: Vec<bool>,
|
pub telepath_tiles: Vec<bool>,
|
||||||
|
|
@ -71,6 +81,7 @@ impl Map {
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
revealed_tiles: vec![false; map_tile_count],
|
revealed_tiles: vec![false; map_tile_count],
|
||||||
|
memory: HashMap::new(),
|
||||||
visible_tiles: vec![false; map_tile_count],
|
visible_tiles: vec![false; map_tile_count],
|
||||||
lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false.
|
lit_tiles: vec![true; map_tile_count], // NYI: Light sources. Once those exist, we can set this to false.
|
||||||
telepath_tiles: vec![false; map_tile_count],
|
telepath_tiles: vec![false; map_tile_count],
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use super::{
|
||||||
Telepath,
|
Telepath,
|
||||||
Viewshed,
|
Viewshed,
|
||||||
Renderable,
|
Renderable,
|
||||||
|
Prop,
|
||||||
|
Item,
|
||||||
gui::renderable_colour,
|
gui::renderable_colour,
|
||||||
tile_blocks_telepathy,
|
tile_blocks_telepathy,
|
||||||
};
|
};
|
||||||
|
|
@ -35,6 +37,8 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
ReadStorage<'a, Blind>,
|
ReadStorage<'a, Blind>,
|
||||||
ReadStorage<'a, BlocksVisibility>,
|
ReadStorage<'a, BlocksVisibility>,
|
||||||
ReadStorage<'a, Renderable>,
|
ReadStorage<'a, Renderable>,
|
||||||
|
ReadStorage<'a, Prop>,
|
||||||
|
ReadStorage<'a, Item>,
|
||||||
);
|
);
|
||||||
|
|
||||||
fn run(&mut self, data: Self::SystemData) {
|
fn run(&mut self, data: Self::SystemData) {
|
||||||
|
|
@ -51,6 +55,8 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
blind_entities,
|
blind_entities,
|
||||||
blocks_visibility,
|
blocks_visibility,
|
||||||
renderables,
|
renderables,
|
||||||
|
prop,
|
||||||
|
item,
|
||||||
) = data;
|
) = data;
|
||||||
|
|
||||||
map.view_blocked.clear();
|
map.view_blocked.clear();
|
||||||
|
|
@ -59,6 +65,7 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
map.view_blocked.insert(idx);
|
map.view_blocked.insert(idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut player_was_dirty = false;
|
||||||
for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() {
|
for (ent, viewshed, pos) in (&entities, &mut viewshed, &pos).join() {
|
||||||
if viewshed.dirty {
|
if viewshed.dirty {
|
||||||
viewshed.dirty = false;
|
viewshed.dirty = false;
|
||||||
|
|
@ -81,6 +88,7 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
// If this is the player, reveal what they can see
|
// If this is the player, reveal what they can see
|
||||||
let _p: Option<&Player> = player.get(ent);
|
let _p: Option<&Player> = player.get(ent);
|
||||||
if let Some(_p) = _p {
|
if let Some(_p) = _p {
|
||||||
|
player_was_dirty = true;
|
||||||
for t in map.visible_tiles.iter_mut() {
|
for t in map.visible_tiles.iter_mut() {
|
||||||
*t = false;
|
*t = false;
|
||||||
}
|
}
|
||||||
|
|
@ -139,6 +147,37 @@ impl<'a> System<'a> for VisibilitySystem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if player_was_dirty {
|
||||||
|
// Refresh the memory of our visible tiles, by removing whatever
|
||||||
|
// was stored for every index we can currently see, and placing
|
||||||
|
// back in updated data.
|
||||||
|
let mut to_remove: Vec<usize> = Vec::new();
|
||||||
|
for (i, &t) in map.visible_tiles.iter().enumerate() {
|
||||||
|
if t {
|
||||||
|
to_remove.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for idx in to_remove.iter() {
|
||||||
|
map.memory.remove(idx);
|
||||||
|
}
|
||||||
|
for (e, r, p, _h) in (&entities, &renderables, &pos, !&hidden).join() {
|
||||||
|
if prop.get(e).is_some() || item.get(e).is_some() {
|
||||||
|
let idx = map.xy_idx(p.x, p.y);
|
||||||
|
if map.visible_tiles[idx] {
|
||||||
|
if let Some(spriteinfo) = &r.sprite {
|
||||||
|
map.memory.entry(idx).or_insert(Vec::new()).push(crate::MapMemory {
|
||||||
|
sprite: spriteinfo.id.clone(),
|
||||||
|
fg: r.fg,
|
||||||
|
recolour: spriteinfo.recolour,
|
||||||
|
offset: spriteinfo.offset,
|
||||||
|
render_order: r.render_order,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue