bracket_terminal::add_wasm_support!();
use bracket_pathfinding::prelude::*;
use bracket_random::prelude::*;
use bracket_terminal::prelude::*;
#[derive(PartialEq, Copy, Clone)]
enum TileType {
Wall,
Floor,
}
const WIDTH: i32 = 40;
const HEIGHT: i32 = 25;
struct State {
map: Vec<TileType>,
player_position: usize,
visible: Vec<bool>,
}
pub fn xy_idx(x: i32, y: i32) -> usize {
(y as usize * WIDTH as usize) + x as usize
}
pub fn idx_xy(idx: usize) -> (i32, i32) {
(idx as i32 % WIDTH, idx as i32 / WIDTH)
}
impl State {
pub fn new() -> State {
let mut state = State {
map: vec![TileType::Floor; (WIDTH * HEIGHT) as usize],
player_position: xy_idx(WIDTH / 2, HEIGHT / 2),
visible: vec![false; (WIDTH * HEIGHT) as usize],
};
for x in 0..WIDTH {
state.map[xy_idx(x, 0)] = TileType::Wall;
state.map[xy_idx(x, HEIGHT - 1)] = TileType::Wall;
}
for y in 0..HEIGHT {
state.map[xy_idx(0, y)] = TileType::Wall;
state.map[xy_idx(WIDTH - 1, y)] = TileType::Wall;
}
let mut rng = RandomNumberGenerator::new();
for _ in 0..400 {
let x = rng.range(1, WIDTH - 1);
let y = rng.range(1, HEIGHT - 1);
let idx = xy_idx(x, y);
if state.player_position != idx {
state.map[idx] = TileType::Wall;
}
}
state
}
pub fn move_player(&mut self, delta_x: i32, delta_y: i32) {
let current_position = idx_xy(self.player_position);
let new_position = (current_position.0 + delta_x, current_position.1 + delta_y);
let new_idx = xy_idx(new_position.0, new_position.1);
if self.map[new_idx] == TileType::Floor {
self.player_position = new_idx;
}
}
}
impl GameState for State {
#[allow(non_snake_case)]
fn tick(&mut self, ctx: &mut BTerm) {
let mut draw_batch = DrawBatch::new();
match ctx.key {
None => {} Some(key) => {
match key {
VirtualKeyCode::Numpad8 => self.move_player(0, -1),
VirtualKeyCode::Numpad4 => self.move_player(-1, 0),
VirtualKeyCode::Numpad6 => self.move_player(1, 0),
VirtualKeyCode::Numpad2 => self.move_player(0, 1),
VirtualKeyCode::Numpad7 => self.move_player(-1, -1),
VirtualKeyCode::Numpad9 => self.move_player(1, -1),
VirtualKeyCode::Numpad1 => self.move_player(-1, 1),
VirtualKeyCode::Numpad3 => self.move_player(1, 1),
VirtualKeyCode::Up => self.move_player(0, -1),
VirtualKeyCode::Down => self.move_player(0, 1),
VirtualKeyCode::Left => self.move_player(-1, 0),
VirtualKeyCode::Right => self.move_player(1, 0),
_ => {} }
}
}
for v in &mut self.visible {
*v = false;
}
let player_position = self.index_to_point2d(self.player_position);
let fov = field_of_view_set(player_position, 8, self);
for idx in &fov {
self.visible[xy_idx(idx.x, idx.y)] = true;
}
draw_batch.target(0);
draw_batch.cls();
let mut y = 0;
let mut x = 0;
for (i, tile) in self.map.iter().enumerate() {
let mut fg = RGB::from_f32(1.0, 1.0, 1.0);
let glyph;
match tile {
TileType::Floor => {
glyph = 0;
}
TileType::Wall => {
glyph = 1;
}
}
if !self.visible[i] {
fg = fg * 0.3;
} else {
let distance = 1.0
- (DistanceAlg::Pythagoras.distance2d(Point::new(x, y), player_position)
as f32
/ 10.0);
fg = RGB::from_f32(distance, distance, distance);
}
draw_batch.set(
Point::new(x, y),
ColorPair::new(fg, RGB::from_f32(0., 0., 0.)),
glyph,
);
x += 1;
if x > WIDTH - 1 {
x = 0;
y += 1;
}
}
let ppos = idx_xy(self.player_position);
draw_batch.target(1);
draw_batch.cls();
draw_batch.set(
Point::from_tuple(ppos),
ColorPair::new(RGB::from_f32(1.0, 1.0, 1.0), RGB::from_f32(0., 0., 0.)),
2,
);
draw_batch.submit(0).expect("Batch error");
render_draw_buffer(ctx).expect("Render error");
}
}
impl BaseMap for State {
fn is_opaque(&self, idx: usize) -> bool {
self.map[idx as usize] == TileType::Wall
}
}
impl Algorithm2D for State {
fn dimensions(&self) -> Point {
Point::new(WIDTH, HEIGHT)
}
}
bracket_terminal::embedded_resource!(TILE_FONT, "../resources/example_tiles.png");
fn main() -> BError {
bracket_terminal::link_resource!(TILE_FONT, "resources/example_tiles.png");
let context = BTermBuilder::new()
.with_dimensions(WIDTH as u32, HEIGHT as u32)
.with_tile_dimensions(16u32, 16u32)
.with_title("Bracket Example - Tiles")
.with_font("example_tiles.png", 16u32, 16u32)
.with_simple_console(WIDTH as u32, HEIGHT as u32, "example_tiles.png")
.with_sparse_console_no_bg(WIDTH as u32, HEIGHT as u32, "example_tiles.png")
.build()?;
let gs = State::new();
main_loop(context, gs)
}