Add simple random map

This commit is contained in:
Alex Page 2022-01-25 17:21:02 -05:00
parent 875948519f
commit 0ee6fc1afe
3 changed files with 192 additions and 33 deletions

View file

@ -1,19 +1,19 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use bracket_lib::prelude::*; use bracket_lib::prelude::*;
use map::{Map, TileType, MAP_HEIGHT, MAP_WIDTH, MAP_X, MAP_Y};
use sound::{Sound, SoundEffect, SoundEffectSamples, SoundSystem}; use sound::{Sound, SoundEffect, SoundEffectSamples, SoundSystem};
use specs::prelude::*; use specs::prelude::*;
use specs_derive::Component; use specs_derive::Component;
use std::{ use std::{
array, array, iter,
cmp::{max, min},
iter,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
use vga_color as vga; use vga_color as vga;
use crate::sound::SoundType; use crate::sound::SoundType;
mod map;
mod sidebar; mod sidebar;
mod sound; mod sound;
pub mod vga_color; pub mod vga_color;
@ -25,6 +25,7 @@ struct SoundEffects {
step_sound: SoundEffectSamples, step_sound: SoundEffectSamples,
pickup_sound: SoundEffectSamples, pickup_sound: SoundEffectSamples,
bad_key_sound: SoundEffectSamples, bad_key_sound: SoundEffectSamples,
blocked_sound: SoundEffectSamples,
} }
#[derive(Component)] #[derive(Component)]
@ -61,23 +62,40 @@ struct State {
fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World, sound_system: &mut SoundSystem) { fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World, sound_system: &mut SoundSystem) {
let mut positions = ecs.write_storage::<Position>(); let mut positions = ecs.write_storage::<Position>();
let mut players = ecs.write_storage::<Player>(); let mut players = ecs.write_storage::<Player>();
let map = ecs.fetch::<Map>();
let mut stepped = false;
for (player, pos) in (&mut players, &mut positions).join() { for (player, pos) in (&mut players, &mut positions).join() {
let now = Instant::now(); let now = Instant::now();
if now - player.last_moved > Duration::from_secs_f32(1. / 7.5) { if now - player.last_moved > Duration::from_secs_f32(0.15) {
pos.x = min(65, max(0, pos.x + delta_x)); let destination_x = pos.x + delta_x;
pos.y = min(24, max(0, pos.y + delta_y)); let destination_y = pos.y + delta_y;
stepped = true;
let sound_effects = ecs.fetch::<SoundEffects>();
if destination_x < 0
|| (destination_x as usize) >= MAP_WIDTH
|| destination_y < 0
|| (destination_y as usize) >= MAP_HEIGHT
{
let blocked_sound = sound_effects.blocked_sound.clone();
sound_system.play_sound(blocked_sound);
player.last_moved = now; player.last_moved = now;
} continue;
} }
if stepped { let destination_tile = map.tile_at(destination_x as usize, destination_y as usize);
let sound_effects = ecs.fetch::<SoundEffects>(); if destination_tile != TileType::Wall {
pos.x = destination_x;
pos.y = destination_y;
let step_sound = sound_effects.step_sound.clone(); let step_sound = sound_effects.step_sound.clone();
sound_system.play_sound(step_sound); sound_system.play_sound(step_sound);
} else {
let blocked_sound = sound_effects.blocked_sound.clone();
sound_system.play_sound(blocked_sound);
}
player.last_moved = now;
}
} }
} }
@ -89,24 +107,35 @@ fn player_input(gs: &mut State, ctx: &mut BTerm) {
VirtualKeyCode::Left | VirtualKeyCode::J => { VirtualKeyCode::Left | VirtualKeyCode::J => {
try_move_player(-1, 0, &mut gs.ecs, &mut gs.sound_system); try_move_player(-1, 0, &mut gs.ecs, &mut gs.sound_system);
} }
VirtualKeyCode::U => try_move_player(-1, -1, &mut gs.ecs, &mut gs.sound_system), VirtualKeyCode::U | VirtualKeyCode::Home => {
try_move_player(-1, -1, &mut gs.ecs, &mut gs.sound_system)
}
VirtualKeyCode::Up | VirtualKeyCode::I => { VirtualKeyCode::Up | VirtualKeyCode::I => {
try_move_player(0, -1, &mut gs.ecs, &mut gs.sound_system); try_move_player(0, -1, &mut gs.ecs, &mut gs.sound_system);
} }
VirtualKeyCode::O => try_move_player(1, -1, &mut gs.ecs, &mut gs.sound_system), VirtualKeyCode::O | VirtualKeyCode::PageUp => {
try_move_player(1, -1, &mut gs.ecs, &mut gs.sound_system)
}
VirtualKeyCode::Right | VirtualKeyCode::K => { VirtualKeyCode::Right | VirtualKeyCode::K => {
try_move_player(1, 0, &mut gs.ecs, &mut gs.sound_system); try_move_player(1, 0, &mut gs.ecs, &mut gs.sound_system);
} }
VirtualKeyCode::Comma => try_move_player(1, 1, &mut gs.ecs, &mut gs.sound_system), VirtualKeyCode::Comma | VirtualKeyCode::PageDown => {
try_move_player(1, 1, &mut gs.ecs, &mut gs.sound_system)
}
VirtualKeyCode::Down | VirtualKeyCode::M => { VirtualKeyCode::Down | VirtualKeyCode::M => {
try_move_player(0, 1, &mut gs.ecs, &mut gs.sound_system); try_move_player(0, 1, &mut gs.ecs, &mut gs.sound_system);
} }
VirtualKeyCode::N => try_move_player(-1, 1, &mut gs.ecs, &mut gs.sound_system), VirtualKeyCode::N | VirtualKeyCode::End => {
try_move_player(-1, 1, &mut gs.ecs, &mut gs.sound_system)
}
VirtualKeyCode::S => { VirtualKeyCode::S => {
let sound_effects = gs.ecs.fetch::<SoundEffects>(); let sound_effects = gs.ecs.fetch::<SoundEffects>();
let pickup_sound = sound_effects.pickup_sound.clone(); let pickup_sound = sound_effects.pickup_sound.clone();
gs.sound_system.play_sound(pickup_sound); gs.sound_system.play_sound(pickup_sound);
} }
VirtualKeyCode::Escape => {
ctx.quit();
}
_ => { _ => {
let sound_effects = gs.ecs.fetch::<SoundEffects>(); let sound_effects = gs.ecs.fetch::<SoundEffects>();
let bad_key_sound = sound_effects.bad_key_sound.clone(); let bad_key_sound = sound_effects.bad_key_sound.clone();
@ -123,11 +152,20 @@ impl GameState for State {
player_input(self, ctx); player_input(self, ctx);
self.run_systems(); self.run_systems();
let map = self.ecs.fetch::<Map>();
map.draw(ctx);
let positions = self.ecs.read_storage::<Position>(); let positions = self.ecs.read_storage::<Position>();
let renderables = self.ecs.read_storage::<Renderable>(); let renderables = self.ecs.read_storage::<Renderable>();
for (pos, render) in (&positions, &renderables).join() { for (pos, render) in (&positions, &renderables).join() {
ctx.set(pos.x, pos.y, render.fg, render.bg, render.glyph); ctx.set(
pos.x + MAP_X as i32,
pos.y + MAP_Y as i32,
render.fg,
render.bg,
render.glyph,
);
} }
sidebar::draw(&self.ecs, ctx); sidebar::draw(&self.ecs, ctx);
@ -218,6 +256,17 @@ fn main() -> BError {
.collect(), .collect(),
}); });
let blocked_sound = ss.render_sound_effect(&SoundEffect {
sounds: (30..=60)
.rev()
.step_by(6)
.map(|x| Sound {
sound_type: SoundType::Tone(x),
duration: Duration::from_millis(18),
})
.collect(),
});
let mut gs = State { let mut gs = State {
ecs: World::new(), ecs: World::new(),
// sound_sender: tx, // sound_sender: tx,
@ -230,7 +279,9 @@ fn main() -> BError {
step_sound, step_sound,
pickup_sound, pickup_sound,
bad_key_sound, bad_key_sound,
blocked_sound,
}); });
gs.ecs.insert(Map::new());
gs.ecs.register::<Position>(); gs.ecs.register::<Position>();
gs.ecs.register::<Renderable>(); gs.ecs.register::<Renderable>();
@ -239,7 +290,7 @@ fn main() -> BError {
gs.ecs gs.ecs
.create_entity() .create_entity()
.with(Position { x: 40, y: 24 }) .with(Position { x: 40, y: 22 })
.with(Renderable { .with(Renderable {
glyph: to_cp437('☻'), glyph: to_cp437('☻'),
fg: RGB::named(vga::YELLOW_BRIGHT), fg: RGB::named(vga::YELLOW_BRIGHT),
@ -255,18 +306,18 @@ fn main() -> BError {
}) })
.build(); .build();
for i in 0..10 { // for i in 0..10 {
gs.ecs // gs.ecs
.create_entity() // .create_entity()
.with(Position { x: i * 7, y: 20 }) // .with(Position { x: i * 7, y: 20 })
.with(Renderable { // .with(Renderable {
glyph: to_cp437('Ä'), // glyph: to_cp437('Ä'),
fg: RGB::named(vga::RED_BRIGHT), // fg: RGB::named(vga::RED_BRIGHT),
bg: RGB::named(vga::BLACK), // bg: RGB::named(vga::BLACK),
}) // })
.with(LeftMover {}) // .with(LeftMover {})
.build(); // .build();
} // }
// let descent_sounds: Vec<Sound> = (20..100) // let descent_sounds: Vec<Sound> = (20..100)
// .rev() // .rev()

86
src/map.rs Normal file
View file

@ -0,0 +1,86 @@
use crate::vga_color as vga;
use bracket_lib::{
prelude::{to_cp437, BTerm, Rect, RGB},
random::RandomNumberGenerator,
};
pub const MAP_WIDTH: usize = 64;
pub const MAP_HEIGHT: usize = 23;
const MAP_SIZE: usize = MAP_WIDTH * MAP_HEIGHT;
pub const MAP_X: usize = 1;
pub const MAP_Y: usize = 1;
#[derive(PartialEq, Copy, Clone)]
pub enum TileType {
Wall,
Floor,
}
pub struct Map {
tiles: Vec<TileType>,
border_fg: RGB,
border_bg: RGB,
}
impl Map {
pub fn new() -> Self {
let mut tiles = vec![TileType::Floor; MAP_SIZE];
let mut rng = RandomNumberGenerator::new();
for tile in &mut tiles {
if rng.roll_dice(1, 4) < 2 {
*tile = TileType::Wall;
}
}
Self {
tiles,
border_fg: RGB::named(vga::get_by_index(rng.range(8, 15))),
border_bg: RGB::named(vga::get_by_index(rng.range(1, 7) as usize)),
}
}
pub fn draw(&self, ctx: &mut BTerm) {
// Border
ctx.fill_region(
Rect {
x1: MAP_X as i32 - 1,
x2: MAP_WIDTH as i32 + MAP_X as i32 + 1,
y1: MAP_Y as i32 - 1,
y2: MAP_HEIGHT as i32 + MAP_Y as i32 + 1,
},
to_cp437('▓'),
self.border_fg,
self.border_bg,
);
for (i, tile) in self.tiles.iter().enumerate() {
let x = i % MAP_WIDTH;
let y = (i - x) / MAP_WIDTH;
match tile {
TileType::Floor => {
ctx.set(
x + MAP_X,
y + MAP_Y,
RGB::named(vga::BLACK),
RGB::named(vga::BLACK),
to_cp437(' '),
);
}
TileType::Wall => {
ctx.set(
x + MAP_X,
y + MAP_Y,
RGB::named(vga::YELLOW),
RGB::named(vga::BLACK),
to_cp437('▓'),
);
}
}
}
}
pub fn tile_at(&self, x: usize, y: usize) -> TileType {
self.tiles[(y * MAP_WIDTH) + x]
}
}

View file

@ -55,3 +55,25 @@ pub const MAGENTA_BRIGHT: (u8, u8, u8) = (255, 85, 255);
pub const YELLOW_BRIGHT: (u8, u8, u8) = (255, 255, 85); pub const YELLOW_BRIGHT: (u8, u8, u8) = (255, 255, 85);
/// Index `15` /// Index `15`
pub const WHITE_BRIGHT: (u8, u8, u8) = (255, 255, 255); pub const WHITE_BRIGHT: (u8, u8, u8) = (255, 255, 255);
pub fn get_by_index(index: usize) -> (u8, u8, u8) {
match index {
0 => BLACK,
1 => BLUE,
2 => GREEN,
3 => CYAN,
4 => RED,
5 => MAGENTA,
6 => YELLOW,
7 => WHITE,
8 => BLACK_BRIGHT,
9 => BLUE_BRIGHT,
10 => GREEN_BRIGHT,
11 => CYAN_BRIGHT,
12 => RED_BRIGHT,
13 => MAGENTA_BRIGHT,
14 => YELLOW_BRIGHT,
15 => WHITE_BRIGHT,
_ => BLACK,
}
}