Add simple random map
This commit is contained in:
parent
875948519f
commit
0ee6fc1afe
3 changed files with 192 additions and 33 deletions
111
src/main.rs
111
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,23 +62,40 @@ 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::<Position>();
|
||||
let mut players = ecs.write_storage::<Player>();
|
||||
|
||||
let mut stepped = false;
|
||||
let map = ecs.fetch::<Map>();
|
||||
|
||||
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::<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;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if stepped {
|
||||
let sound_effects = ecs.fetch::<SoundEffects>();
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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::<SoundEffects>();
|
||||
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::<SoundEffects>();
|
||||
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>();
|
||||
map.draw(ctx);
|
||||
|
||||
let positions = self.ecs.read_storage::<Position>();
|
||||
let renderables = self.ecs.read_storage::<Renderable>();
|
||||
|
||||
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::<Position>();
|
||||
gs.ecs.register::<Renderable>();
|
||||
|
@ -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<Sound> = (20..100)
|
||||
// .rev()
|
||||
|
|
86
src/map.rs
Normal file
86
src/map.rs
Normal 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]
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue