From 0ee6fc1afea7b1133d703b497d1ea5e90e3024de Mon Sep 17 00:00:00 2001 From: Alex Page Date: Tue, 25 Jan 2022 17:21:02 -0500 Subject: [PATCH] Add simple random map --- src/main.rs | 117 ++++++++++++++++++++++++++++++++++------------- src/map.rs | 86 ++++++++++++++++++++++++++++++++++ src/vga_color.rs | 22 +++++++++ 3 files changed, 192 insertions(+), 33 deletions(-) create mode 100644 src/map.rs diff --git a/src/main.rs b/src/main.rs index ba8f74e..369315c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,19 +1,19 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] use bracket_lib::prelude::*; +use map::{Map, TileType, MAP_HEIGHT, MAP_WIDTH, MAP_X, MAP_Y}; use sound::{Sound, SoundEffect, SoundEffectSamples, SoundSystem}; use specs::prelude::*; use specs_derive::Component; use std::{ - array, - cmp::{max, min}, - iter, + array, iter, time::{Duration, Instant}, }; use vga_color as vga; use crate::sound::SoundType; +mod map; mod sidebar; mod sound; pub mod vga_color; @@ -25,6 +25,7 @@ struct SoundEffects { step_sound: SoundEffectSamples, pickup_sound: SoundEffectSamples, bad_key_sound: SoundEffectSamples, + blocked_sound: SoundEffectSamples, } #[derive(Component)] @@ -61,24 +62,41 @@ struct State { fn try_move_player(delta_x: i32, delta_y: i32, ecs: &mut World, sound_system: &mut SoundSystem) { let mut positions = ecs.write_storage::(); let mut players = ecs.write_storage::(); - - let mut stepped = false; + let map = ecs.fetch::(); for (player, pos) in (&mut players, &mut positions).join() { let now = Instant::now(); - if now - player.last_moved > Duration::from_secs_f32(1. / 7.5) { - pos.x = min(65, max(0, pos.x + delta_x)); - pos.y = min(24, max(0, pos.y + delta_y)); - stepped = true; + if now - player.last_moved > Duration::from_secs_f32(0.15) { + let destination_x = pos.x + delta_x; + let destination_y = pos.y + delta_y; + + let sound_effects = ecs.fetch::(); + + 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; + continue; + } + + let destination_tile = map.tile_at(destination_x as usize, destination_y as usize); + if destination_tile != TileType::Wall { + pos.x = destination_x; + pos.y = destination_y; + + let step_sound = sound_effects.step_sound.clone(); + 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; } } - - if stepped { - let sound_effects = ecs.fetch::(); - let step_sound = sound_effects.step_sound.clone(); - sound_system.play_sound(step_sound); - } } fn player_input(gs: &mut State, ctx: &mut BTerm) { @@ -89,24 +107,35 @@ fn player_input(gs: &mut State, ctx: &mut BTerm) { VirtualKeyCode::Left | VirtualKeyCode::J => { 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 => { 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 => { 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 => { 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 => { let sound_effects = gs.ecs.fetch::(); let pickup_sound = sound_effects.pickup_sound.clone(); gs.sound_system.play_sound(pickup_sound); } + VirtualKeyCode::Escape => { + ctx.quit(); + } _ => { let sound_effects = gs.ecs.fetch::(); let bad_key_sound = sound_effects.bad_key_sound.clone(); @@ -123,11 +152,20 @@ impl GameState for State { player_input(self, ctx); self.run_systems(); + let map = self.ecs.fetch::(); + map.draw(ctx); + let positions = self.ecs.read_storage::(); let renderables = self.ecs.read_storage::(); 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); @@ -218,6 +256,17 @@ fn main() -> BError { .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 { ecs: World::new(), // sound_sender: tx, @@ -230,7 +279,9 @@ fn main() -> BError { step_sound, pickup_sound, bad_key_sound, + blocked_sound, }); + gs.ecs.insert(Map::new()); gs.ecs.register::(); gs.ecs.register::(); @@ -239,7 +290,7 @@ fn main() -> BError { gs.ecs .create_entity() - .with(Position { x: 40, y: 24 }) + .with(Position { x: 40, y: 22 }) .with(Renderable { glyph: to_cp437('☻'), fg: RGB::named(vga::YELLOW_BRIGHT), @@ -255,18 +306,18 @@ fn main() -> BError { }) .build(); - for i in 0..10 { - gs.ecs - .create_entity() - .with(Position { x: i * 7, y: 20 }) - .with(Renderable { - glyph: to_cp437('Ä'), - fg: RGB::named(vga::RED_BRIGHT), - bg: RGB::named(vga::BLACK), - }) - .with(LeftMover {}) - .build(); - } + // for i in 0..10 { + // gs.ecs + // .create_entity() + // .with(Position { x: i * 7, y: 20 }) + // .with(Renderable { + // glyph: to_cp437('Ä'), + // fg: RGB::named(vga::RED_BRIGHT), + // bg: RGB::named(vga::BLACK), + // }) + // .with(LeftMover {}) + // .build(); + // } // let descent_sounds: Vec = (20..100) // .rev() diff --git a/src/map.rs b/src/map.rs new file mode 100644 index 0000000..1906e0f --- /dev/null +++ b/src/map.rs @@ -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, + 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] + } +} diff --git a/src/vga_color.rs b/src/vga_color.rs index 530df2b..35fe7f6 100644 --- a/src/vga_color.rs +++ b/src/vga_color.rs @@ -55,3 +55,25 @@ pub const MAGENTA_BRIGHT: (u8, u8, u8) = (255, 85, 255); pub const YELLOW_BRIGHT: (u8, u8, u8) = (255, 255, 85); /// Index `15` 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, + } +}