camera rendering, and breaking things temporarily

This commit is contained in:
Llywelwyn 2023-09-24 14:23:48 +01:00
parent 1299524c91
commit d9489e7ddc
6 changed files with 202 additions and 217 deletions

View file

@ -7,7 +7,20 @@ use super::data::prelude::*;
const SHOW_BOUNDARIES: bool = false;
pub fn get_screen_bounds(ecs: &World) -> (i32, i32, i32, i32, i32, i32) {
pub fn get_offset() -> (i32, i32) {
return (1, 10);
}
pub struct ScreenBounds {
pub min_x: i32,
pub max_x: i32,
pub min_y: i32,
pub max_y: i32,
pub x_offset: i32,
pub y_offset: i32,
}
pub fn get_screen_bounds(ecs: &World) -> ScreenBounds {
let player_pos = ecs.fetch::<Point>();
let map = ecs.fetch::<Map>();
let (x_chars, y_chars, mut x_offset, mut y_offset) = (VIEWPORT_W, VIEWPORT_H, 1, 10);
@ -30,7 +43,11 @@ pub fn get_screen_bounds(ecs: &World) -> (i32, i32, i32, i32, i32, i32) {
let max_x = min_x + (x_chars as i32);
let max_y = min_y + (y_chars as i32);
(min_x, max_x, min_y, max_y, x_offset, y_offset)
ScreenBounds { min_x, max_x, min_y, max_y, x_offset, y_offset }
}
pub fn in_bounds(x: i32, y: i32, upper_x: i32, upper_y: i32) -> bool {
x >= 0 && x < upper_x && y >= 0 && y < upper_y
}
pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
@ -64,7 +81,7 @@ pub fn render_camera(ecs: &World, ctx: &mut BTerm) {
Rect::with_size(x * 16 + x_offset * 16, y * 16 + y_offset * 16, 16, 16),
0,
tint,
id
0 // Ya
);
ctx.set_active_console(TILE_LAYER);
}

View file

@ -146,18 +146,60 @@ fn setup(gfx: &mut Graphics) -> State {
gs
}
const ASCII_MODE: bool = false; // Change this to config setting
const SHOW_BOUNDARIES: bool = false; // Config setting
use notan::draw::Draw;
fn draw_camera(ecs: &World, draw: &mut Draw, atlas: &HashMap<String, Texture>) {
let map = ecs.fetch::<Map>();
let bounds = crate::camera::get_screen_bounds(ecs);
render_map_in_view(&*map, ecs, draw, bounds);
}
use crate::camera::ScreenBounds;
fn render_map_in_view(map: &Map, ecs: &World, draw: &mut Draw, bounds: ScreenBounds) {
for tile_y in bounds.min_y..bounds.max_y {
for tile_x in bounds.min_x..bounds.max_x {
if crate::camera::in_bounds(tile_x, tile_y, map.width, map.height) {
let idx = map.xy_idx(tile_x, tile_y);
if map.revealed_tiles[idx] {
if ASCII_MODE {
let (glyph, fg, bg) = crate::map::themes::get_tile_renderables_for_id(
idx,
&*map,
Some(*ecs.fetch::<Point>()),
None
);
// TODO: Draw ASCII
} else {
let (id, tint) = crate::map::themes::get_sprite_for_id(
idx,
&*map,
Some(*ecs.fetch::<Point>())
);
let px = idx_to_px(
map.xy_idx(tile_x + bounds.x_offset, tile_y + bounds.y_offset),
&map
);
draw.image(atlas.get(id).unwrap()).position(px.0, px.1);
}
}
} else if SHOW_BOUNDARIES {
// TODO: Draw boundaries
}
}
}
}
fn draw(app: &mut App, gfx: &mut Graphics, gs: &mut State) {
let mut draw = gfx.create_draw();
draw.clear(Color::BLACK);
// Draw map
draw_camera(&gs.ecs, &mut draw, &gs.atlas);
// Draw player (replace this with draw entities).
let map = gs.ecs.fetch::<Map>();
for (i, _tile) in map.tiles.iter().enumerate() {
let px = idx_to_px(i, &map);
draw.image(gs.atlas.get("floor_grass_d").unwrap()).position(px.0, px.1);
}
let ppos = gs.ecs.fetch::<Point>();
let px = idx_to_px(map.xy_idx(ppos.x, ppos.y), &map);
let offsets = crate::camera::get_offset();
let px = idx_to_px(map.xy_idx(ppos.x + offsets.0, ppos.y + offsets.1), &map);
draw.image(gs.atlas.get("ui_heart_full").unwrap()).position(px.0, px.1);
// Render batch
gfx.render(&draw);

View file

@ -5,21 +5,21 @@ use crate::data::ids::*;
use bracket_lib::prelude::*;
use std::ops::{ Add, Mul };
pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option<Point>) -> (usize, RGBA) {
pub fn get_sprite_for_id(idx: usize, map: &Map, other_pos: Option<Point>) -> (&str, RGBA) {
let x = (idx as i32) % map.width;
let y = (idx as i32) / map.width;
let tile = map.tiles[idx];
let base = match tile {
let sprite = map.tiles[idx].sprite();
/*let base = match tile {
TileType::Wall => wall_sprite(tile.sprite(), map, x, y),
_ => tile.sprite(),
};
let sprite_id = pick_variant(base, tile.variants(), idx, map);
let sprite_id = pick_variant(base, tile.variants(), idx, map);*/
let tint = if !map.visible_tiles[idx] {
RGBA::from_f32(0.75, 0.75, 0.75, 1.0)
} else {
RGBA::named(WHITE)
};
return (sprite_id, tint);
return (sprite, tint);
}
/// Gets the renderables for a tile, with darkening/offset/post-processing/etc. Passing a val for "debug" will ignore viewshed.
pub fn get_tile_renderables_for_id(

View file

@ -30,27 +30,27 @@ pub enum TileType {
}
impl TileType {
pub fn sprite(&self) -> usize {
pub fn sprite(&self) -> &str {
match self {
TileType::ImpassableMountain => STATUE,
TileType::Wall => WALL_BASE,
TileType::DeepWater => WATER_DEEP,
TileType::Fence => WALL_BASE,
TileType::Bars => WALL_BASE,
TileType::Floor => FLOOR,
TileType::WoodFloor => FLOOR_WOOD,
TileType::Gravel => FLOOR,
TileType::Road => PATH_GRASS,
TileType::Grass => FLOOR_GRASS,
TileType::Foliage => FLOOR_GRASS,
TileType::HeavyFoliage => FLOOR_GRASS,
TileType::Sand => FLOOR,
TileType::ShallowWater => WATER_DEEP,
TileType::Bridge => FLOOR,
TileType::DownStair => STAIR_D,
TileType::UpStair => STAIR_A,
TileType::ToLocal(_) => MUSHROOM,
TileType::ToOvermap(_) => MUSHROOM_ORANGE,
TileType::ImpassableMountain => "statue_warrior",
TileType::Wall => "wall_cave_h_a",
TileType::DeepWater => "water",
TileType::Fence => "wall_cave_h_a",
TileType::Bars => "wall_cave_h_a",
TileType::Floor => "floor_cobble_a",
TileType::WoodFloor => "floor_wood_a",
TileType::Gravel => "floor_cobble_b",
TileType::Road => "floor_cobble_c",
TileType::Grass => "floor_grass_a",
TileType::Foliage => "floor_grass_b",
TileType::HeavyFoliage => "floor_grass_c",
TileType::Sand => "floor_cobble_c",
TileType::ShallowWater => "water",
TileType::Bridge => "floor_cobble_a",
TileType::DownStair => "wall_cave_stair_down",
TileType::UpStair => "wall_cave_stair_up",
TileType::ToLocal(_) => "wall_crypt_stair_down",
TileType::ToOvermap(_) => "wall_crypt_stair_up",
}
}

View file

@ -40,6 +40,8 @@ use std::cmp::{ max, min };
use crate::data::events::*;
use crate::data::ids::*;
use crate::gui::with_article;
use notan::prelude::*;
use std::collections::HashMap;
pub fn try_door(i: i32, j: i32, ecs: &mut World) -> RunState {
let mut positions = ecs.write_storage::<Position>();
@ -645,195 +647,117 @@ fn get_item(ecs: &mut World) -> RunState {
}
}
use notan::prelude::*;
fn try_descend(ecs: &mut World) -> RunState {
let dest = try_change_level(ecs, false);
let curr_map_id = ecs.fetch::<Map>().id;
return match dest {
Destination::None => RunState::AwaitingInput,
Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
Destination::PreviousLevel => RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
}
fn try_ascend(ecs: &mut World) -> RunState {
let dest = try_change_level(ecs, true);
let curr_map_id = ecs.fetch::<Map>().id;
return match dest {
Destination::None => RunState::AwaitingInput,
Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
Destination::PreviousLevel => RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
}
pub fn player_input(gs: &mut State, ctx: &mut App, on_overmap: bool) -> RunState {
let key = &ctx.keyboard;
if key.was_pressed(KeyCode::Numpad4) {
return try_move_player(-1, 0, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad6) {
return try_move_player(1, 0, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad8) {
return try_move_player(0, -1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad2) {
return try_move_player(0, 1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad9) {
return try_move_player(1, -1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad7) {
return try_move_player(-1, -1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad3) {
return try_move_player(1, 1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Numpad1) {
return try_move_player(-1, 1, &mut gs.ecs);
} else if key.was_pressed(KeyCode::Period) {
if key.shift() {
let dest = try_change_level(&mut gs.ecs, false);
let curr_map_id = gs.ecs.fetch::<Map>().id;
return match dest {
// If we have no destination, do nothing.
Destination::None => RunState::AwaitingInput,
// If we want to go to the next level, go to the up-stair tile of id + 1.
Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
// If we want to go to the previous level, go to the down-stair tile of id - 1.
Destination::PreviousLevel =>
RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
} else {
return skip_turn(&mut gs.ecs); // (Wait a turn)
}
} else if key.was_pressed(KeyCode::Comma) {
if key.shift() {
let dest = try_change_level(&mut gs.ecs, false);
let curr_map_id = gs.ecs.fetch::<Map>().id;
return match dest {
// If we have no destination, do nothing.
Destination::None => RunState::AwaitingInput,
// If we want to go to the next level, go to the up-stair tile of id + 1.
Destination::NextLevel => RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
// If we want to go to the previous level, go to the down-stair tile of id - 1.
Destination::PreviousLevel =>
RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) => RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) => RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
} else {
return skip_turn(&mut gs.ecs); // (Wait a turn)
}
}
return RunState::AwaitingInput;
/*match ctx.key {
None => {
return RunState::AwaitingInput;
}
Some(key) =>
match key {
// Cardinals
VirtualKeyCode::Left | VirtualKeyCode::Numpad4 | VirtualKeyCode::H => {
return try_move_player(-1, 0, &mut gs.ecs);
}
VirtualKeyCode::Right | VirtualKeyCode::Numpad6 | VirtualKeyCode::L => {
return try_move_player(1, 0, &mut gs.ecs);
}
VirtualKeyCode::Up | VirtualKeyCode::Numpad8 | VirtualKeyCode::K => {
return try_move_player(0, -1, &mut gs.ecs);
}
VirtualKeyCode::Down | VirtualKeyCode::Numpad2 | VirtualKeyCode::J => {
return try_move_player(0, 1, &mut gs.ecs);
}
// Diagonals
VirtualKeyCode::Numpad9 | VirtualKeyCode::U => {
return try_move_player(1, -1, &mut gs.ecs);
}
VirtualKeyCode::Numpad7 | VirtualKeyCode::Y => {
return try_move_player(-1, -1, &mut gs.ecs);
}
VirtualKeyCode::Numpad3 | VirtualKeyCode::N => {
return try_move_player(1, 1, &mut gs.ecs);
}
VirtualKeyCode::Numpad1 | VirtualKeyCode::B => {
// Movement
for keycode in key.pressed.iter() {
match *keycode {
KeyCode::Numpad1 | KeyCode::B => {
return try_move_player(-1, 1, &mut gs.ecs);
}
// id
VirtualKeyCode::Period => {
if ctx.shift {
let dest = try_change_level(&mut gs.ecs, false);
let curr_map_id = gs.ecs.fetch::<Map>().id;
return match dest {
// If we have no destination, do nothing.
Destination::None => RunState::AwaitingInput,
// If we want to go to the next level, go to the up-stair tile of id + 1.
Destination::NextLevel =>
RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
// If we want to go to the previous level, go to the down-stair tile of id - 1.
Destination::PreviousLevel =>
RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) =>
RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) =>
RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
} else {
return skip_turn(&mut gs.ecs); // (Wait a turn)
KeyCode::Numpad2 | KeyCode::Down | KeyCode::J => {
return try_move_player(0, 1, &mut gs.ecs);
}
KeyCode::Numpad3 | KeyCode::N => {
return try_move_player(1, 1, &mut gs.ecs);
}
KeyCode::Numpad4 | KeyCode::Left | KeyCode::H => {
return try_move_player(-1, 0, &mut gs.ecs);
}
KeyCode::Numpad6 | KeyCode::Right | KeyCode::L => {
return try_move_player(1, 0, &mut gs.ecs);
}
KeyCode::Numpad7 | KeyCode::Y => {
return try_move_player(-1, -1, &mut gs.ecs);
}
KeyCode::Numpad8 | KeyCode::Up | KeyCode::K => {
return try_move_player(0, -1, &mut gs.ecs);
}
KeyCode::Numpad9 | KeyCode::U => {
return try_move_player(1, -1, &mut gs.ecs);
}
KeyCode::Period => {
if key.shift() {
return try_descend(&mut gs.ecs);
}
return skip_turn(&mut gs.ecs);
}
KeyCode::Comma => {
if key.shift() {
return try_ascend(&mut gs.ecs);
}
}
VirtualKeyCode::Comma => {
if ctx.shift {
let dest = try_change_level(&mut gs.ecs, true);
let curr_map_id = gs.ecs.fetch::<Map>().id;
return match dest {
Destination::None => RunState::AwaitingInput,
Destination::NextLevel =>
RunState::GoToLevel(curr_map_id + 1, TileType::UpStair),
Destination::PreviousLevel =>
RunState::GoToLevel(curr_map_id - 1, TileType::DownStair),
Destination::ToLocal(id) =>
RunState::GoToLevel(ID_OVERMAP, TileType::ToLocal(id)),
Destination::ToOvermap(id) =>
RunState::GoToLevel(id, TileType::ToOvermap(id)),
};
}
}
VirtualKeyCode::Slash => {
if ctx.shift {
KeyCode::Slash => {
if key.shift() {
return RunState::HelpScreen;
}
}
VirtualKeyCode::NumpadDecimal => {
return skip_turn(&mut gs.ecs);
}
// Items
VirtualKeyCode::C => {
KeyCode::C => {
if !on_overmap {
return RunState::ActionWithDirection { function: try_door };
}
}
VirtualKeyCode::O => {
KeyCode::O => {
if !on_overmap {
return RunState::ActionWithDirection { function: open };
}
}
VirtualKeyCode::F => {
KeyCode::F => {
if !on_overmap {
return RunState::ActionWithDirection { function: kick };
}
}
VirtualKeyCode::G => {
KeyCode::G => {
return get_item(&mut gs.ecs);
}
VirtualKeyCode::I => {
KeyCode::I => {
return RunState::ShowInventory;
}
VirtualKeyCode::D => {
KeyCode::D => {
return RunState::ShowDropItem;
}
VirtualKeyCode::R => {
KeyCode::R => {
return RunState::ShowRemoveItem;
}
// Other
VirtualKeyCode::Minus => {
KeyCode::Minus => {
return RunState::ShowCheatMenu;
}
VirtualKeyCode::Escape => {
KeyCode::Escape => {
return RunState::SaveGame;
}
VirtualKeyCode::X => {
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(
&gs.ecs,
ctx
);
KeyCode::X => {
let (min_x, _max_x, min_y, _max_y, x_offset, y_offset) = get_screen_bounds(&gs.ecs);
let ppos = gs.ecs.fetch::<Point>();
let (x, y) = (ppos.x + x_offset - min_x, ppos.y + y_offset - min_y);
return RunState::Farlook { x, y };
}
_ => {
_ => {}
}
}
return RunState::AwaitingInput;
}
}
}
return RunState::AwaitingInput;*/
}
fn try_change_level(ecs: &mut World, backtracking: bool) -> Destination {

View file

@ -296,6 +296,8 @@ impl State {
}
damage_system::delete_the_dead(&mut self.ecs);
}
// Deprecated
fn tick(&mut self, ctx: &mut BTerm) {
let mut new_runstate;
{