diff --git a/src/main.rs b/src/main.rs index 5702fbe..ef303ef 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,11 +7,10 @@ use specs::prelude::*; mod entity; mod map; mod player; +mod rect; mod state; -use crate::entity::{ - LeftMover, LeftWalker, Player, Position, Renderable, -}; +use crate::entity::{Player, Position, Renderable}; use crate::state::State; fn main() { @@ -19,20 +18,20 @@ fn main() { Rltk::init_simple8x8(80, 50, "MORTAL WOMBAT", "resources"); let mut gs = State { ecs: World::new(), - systems: DispatcherBuilder::new() - .with(LeftWalker {}, "left_walker", &[]) - .build(), + systems: DispatcherBuilder::new().build(), }; gs.ecs.register::(); gs.ecs.register::(); - gs.ecs.register::(); gs.ecs.register::(); - gs.ecs.insert(map::new()); + let (rooms, map) = map::new_room_corridors(); + gs.ecs.insert(map); + // start player in center of room 1 + let (p_x, p_y) = rooms[0].center(); gs.ecs .create_entity() - .with(Position { x: 40, y: 25 }) + .with(Position { x: p_x, y: p_y }) .with(Renderable { glyph: rltk::to_cp437('@'), fg: RGB::named(rltk::YELLOW), @@ -41,18 +40,5 @@ fn main() { .with(Player {}) .build(); - (0..10).into_iter().for_each(|i| { - gs.ecs - .create_entity() - .with(Position { x: i * 7, y: 20 }) - .with(Renderable { - glyph: rltk::to_cp437('?'), - fg: RGB::named(rltk::RED), - bg: RGB::named(rltk::BLACK), - }) - .with(LeftMover {}) - .build(); - }); - rltk::main_loop(context, gs); } diff --git a/src/map.rs b/src/map.rs index 869d229..d9740c7 100644 --- a/src/map.rs +++ b/src/map.rs @@ -1,12 +1,15 @@ -use rltk::{Console, Rltk, RGB}; +use std::cmp::{max, min}; + +use rltk::{Console, RandomNumberGenerator, Rltk, RGB}; use crate::entity::TileType; +use crate::rect::Rect; pub fn xy_idx(x: i32, y: i32) -> usize { (y as usize * 80) + x as usize } -pub fn new() -> Vec { +pub fn new_test() -> Vec { let mut map = vec![TileType::Floor; 80 * 50]; (0..80).into_iter().for_each(|x| { @@ -34,6 +37,52 @@ pub fn new() -> Vec { map } +pub fn new_room_corridors() -> (Vec, Vec) { + let mut map = vec![TileType::Wall; 80 * 50]; + + let mut rooms: Vec = Vec::new(); + const MAX_ROOMS: i32 = 30; + const MIN_SIZE: i32 = 6; + const MAX_SIZE: i32 = 10; + + let mut rng = RandomNumberGenerator::new(); + + (0..MAX_ROOMS).into_iter().for_each(|_| { + let w = rng.range(MIN_SIZE, MAX_SIZE); + let h = rng.range(MIN_SIZE, MAX_SIZE); + let x = rng.roll_dice(1, 80 - w - 1) - 1; + let y = rng.roll_dice(1, 50 - h - 1) - 1; + + let new_room = Rect::new(x, y, w, h); + let mut ok = true; + rooms.iter().for_each(|other| { + if new_room.intersect(other) { + ok = false; + } + }); + + if ok { + apply_room(&new_room, &mut map); + + if !rooms.is_empty() { + let (new_x, new_y) = new_room.center(); + let (prev_x, prev_y) = rooms[rooms.len() - 1].center(); + + if rng.range(0, 1) == 1 { + apply_horiz_tunnel(&mut map, prev_x, new_x, prev_y); + apply_vert_tunnel(&mut map, prev_y, new_y, new_x); + } else { + apply_vert_tunnel(&mut map, prev_y, new_y, prev_x); + apply_horiz_tunnel(&mut map, prev_x, new_x, new_y); + } + } + rooms.push(new_room); + } + }); + + (rooms, map) +} + pub fn draw(map: &[TileType], ctx: &mut Rltk) { let mut y = 0; let mut x = 0; @@ -66,3 +115,29 @@ pub fn draw(map: &[TileType], ctx: &mut Rltk) { } }); } + +pub fn apply_room(room: &Rect, map: &mut [TileType]) { + (room.y1 + 1..=room.y2).into_iter().for_each(|y| { + (room.x1 + 1..=room.x2).into_iter().for_each(|x| { + map[xy_idx(x, y)] = TileType::Floor; + }); + }); +} + +fn apply_horiz_tunnel(map: &mut [TileType], x1: i32, x2: i32, y: i32) { + (min(x1, x2)..=max(x1, x2)).into_iter().for_each(|x| { + let idx = xy_idx(x, y); + if idx > 0 && idx < 80 * 50 { + map[idx as usize] = TileType::Floor; + } + }); +} + +fn apply_vert_tunnel(map: &mut [TileType], y1: i32, y2: i32, x: i32) { + (min(y1, y2)..=max(y1, y2)).into_iter().for_each(|y| { + let idx = xy_idx(x, y); + if idx > 0 && idx < 80 * 50 { + map[idx as usize] = TileType::Floor; + } + }); +} diff --git a/src/player.rs b/src/player.rs index ae293a4..bab8193 100644 --- a/src/player.rs +++ b/src/player.rs @@ -39,14 +39,18 @@ pub fn input(gs: &mut State, ctx: &mut Rltk) { match ctx.key { None => {} Some(key) => match key { - VirtualKeyCode::Left => { - player::try_move(-1, 0, &mut gs.ecs) - } - VirtualKeyCode::Right => { - player::try_move(1, 0, &mut gs.ecs) - } - VirtualKeyCode::Up => player::try_move(0, -1, &mut gs.ecs), - VirtualKeyCode::Down => player::try_move(0, 1, &mut gs.ecs), + VirtualKeyCode::Left => try_move(-1, 0, &mut gs.ecs), + VirtualKeyCode::Numpad4 => try_move(-1, 0, &mut gs.ecs), + VirtualKeyCode::H => try_move(-1, 0, &mut gs.ecs), + VirtualKeyCode::Right => try_move(1, 0, &mut gs.ecs), + VirtualKeyCode::Numpad6 => try_move(1, 0, &mut gs.ecs), + VirtualKeyCode::L => try_move(1, 0, &mut gs.ecs), + VirtualKeyCode::Up => try_move(0, -1, &mut gs.ecs), + VirtualKeyCode::Numpad8 => try_move(0, -1, &mut gs.ecs), + VirtualKeyCode::K => try_move(0, -1, &mut gs.ecs), + VirtualKeyCode::Down => try_move(0, 1, &mut gs.ecs), + VirtualKeyCode::Numpad2 => try_move(0, 1, &mut gs.ecs), + VirtualKeyCode::J => try_move(0, 1, &mut gs.ecs), _ => {} }, } diff --git a/src/rect.rs b/src/rect.rs new file mode 100644 index 0000000..7d1f227 --- /dev/null +++ b/src/rect.rs @@ -0,0 +1,29 @@ +pub struct Rect { + pub x1: i32, + pub x2: i32, + pub y1: i32, + pub y2: i32, +} + +impl Rect { + pub fn new(x: i32, y: i32, w: i32, h: i32) -> Self { + Rect { + x1: x, + y1: y, + x2: x + w, + y2: y + h, + } + } + + // true if the two overlap + pub fn intersect(&self, other: &Rect) -> bool { + self.x1 <= other.x2 + && self.x2 >= other.x1 + && self.y1 <= other.y2 + && self.y2 >= other.y1 + } + + pub fn center(&self) -> (i32, i32) { + ((self.x1 + self.x2) / 2, (self.y1 + self.y2) / 2) + } +}