parent
91160edb3f
commit
9971d9dee5
|
@ -28,7 +28,7 @@ pub struct Level {
|
||||||
|
|
||||||
impl Level {
|
impl Level {
|
||||||
pub fn new() -> Level {
|
pub fn new() -> Level {
|
||||||
let mut s = [[LevelElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH];
|
let s = [[LevelElement::Wall; LEVEL_HEIGHT]; LEVEL_WIDTH];
|
||||||
Level {
|
Level {
|
||||||
structure: s,
|
structure: s,
|
||||||
start_x: 1,
|
start_x: 1,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::cmp::{max, min};
|
||||||
|
use std::ops::Range;
|
||||||
use rand::prelude::SliceRandom;
|
use rand::prelude::SliceRandom;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use petgraph::graph::UnGraph;
|
use petgraph::graph::UnGraph;
|
||||||
|
@ -13,6 +15,12 @@ const ROOMS_HORIZONTAL: usize = 4;
|
||||||
const ROOM_WIDTH: usize = 7;
|
const ROOM_WIDTH: usize = 7;
|
||||||
const ROOM_HEIGHT: usize = 6;
|
const ROOM_HEIGHT: usize = 6;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
|
struct ConnectionInfo {
|
||||||
|
offset: usize,
|
||||||
|
distance: usize,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
struct Room {
|
struct Room {
|
||||||
pub kind: RoomType,
|
pub kind: RoomType,
|
||||||
|
@ -20,8 +28,8 @@ struct Room {
|
||||||
pub offset_y: usize,
|
pub offset_y: usize,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
// pub connection_down: bool,
|
pub connection_down: Option<ConnectionInfo>,
|
||||||
// pub connection_right: bool,
|
pub connection_right: Option<ConnectionInfo>,
|
||||||
// pub connected: bool,
|
// pub connected: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +41,8 @@ impl Room {
|
||||||
offset_y: 0,
|
offset_y: 0,
|
||||||
width: 0,
|
width: 0,
|
||||||
height: 0,
|
height: 0,
|
||||||
// connection_down: false,
|
connection_down: None,
|
||||||
// connection_right: false,
|
connection_right: None,
|
||||||
// connected: false,
|
// connected: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +55,12 @@ impl Room {
|
||||||
self.offset_x = rng.gen_range(0..(ROOM_WIDTH - width));
|
self.offset_x = rng.gen_range(0..(ROOM_WIDTH - width));
|
||||||
self.offset_y = rng.gen_range(0..(ROOM_HEIGHT - height));
|
self.offset_y = rng.gen_range(0..(ROOM_HEIGHT - height));
|
||||||
}
|
}
|
||||||
|
fn get_x_range(&self) -> Range<usize> {
|
||||||
|
self.offset_x..self.offset_x + self.width
|
||||||
|
}
|
||||||
|
fn get_y_range(&self) -> Range<usize> {
|
||||||
|
self.offset_y..self.offset_y + self.height
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -131,14 +145,58 @@ impl LevelGenerator {
|
||||||
for edge in mst.raw_edges() {
|
for edge in mst.raw_edges() {
|
||||||
let src = mst[edge.source()];
|
let src = mst[edge.source()];
|
||||||
let tgt = mst[edge.target()];
|
let tgt = mst[edge.target()];
|
||||||
println!("{:?} {:?}", src, tgt);
|
|
||||||
|
let src_room = rooms[src.0][src.1];
|
||||||
|
let mut tgt_room = rooms[tgt.0][tgt.1];
|
||||||
|
|
||||||
|
// cols are the same, either up or down
|
||||||
|
if src.0 == tgt.0 {
|
||||||
|
let range = LevelGenerator::range_overlap(src_room.get_x_range(), tgt_room.get_x_range());
|
||||||
|
let position: usize;
|
||||||
|
if range.is_empty() {
|
||||||
|
position = range.start;
|
||||||
|
} else {
|
||||||
|
position = rng.gen_range(range);
|
||||||
|
}
|
||||||
|
if src.1 < tgt.1 {
|
||||||
|
// src to tgt
|
||||||
|
rooms[src.0][src.1].connection_down = Some(ConnectionInfo { offset: position, distance: tgt.1 - src.1 });
|
||||||
|
} else {
|
||||||
|
// tgt to src
|
||||||
|
tgt_room.connection_down = Some(ConnectionInfo { offset: position, distance: src.1 - tgt.1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// rows are the same, either left or right
|
||||||
|
if src.1 == tgt.1 {
|
||||||
|
let range = LevelGenerator::range_overlap(src_room.get_y_range(), tgt_room.get_y_range());
|
||||||
|
let mut position: usize;
|
||||||
|
if range.is_empty() {
|
||||||
|
position = range.start;
|
||||||
|
} else {
|
||||||
|
position = rng.gen_range(range);
|
||||||
|
}
|
||||||
|
if src.1 == 0 && position == 0 {
|
||||||
|
position = 1;
|
||||||
|
}
|
||||||
|
if src.0 < tgt.0 {
|
||||||
|
// src to tgt
|
||||||
|
rooms[src.0][src.1].connection_right = Some(ConnectionInfo { offset: position, distance: tgt.0 - src.0 });
|
||||||
|
} else {
|
||||||
|
// tgt to src
|
||||||
|
tgt_room.connection_right = Some(ConnectionInfo { offset: position, distance: src.1 - tgt.1 });
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// println!("Level {}\n{}", level, Dot::new(&mst));
|
|
||||||
|
|
||||||
LevelGenerator {
|
LevelGenerator {
|
||||||
rooms
|
rooms
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn range_overlap(r1: Range<usize>, r2: Range<usize>) -> Range<usize> {
|
||||||
|
max(r1.start, r2.start)..min(r1.end, r2.end)
|
||||||
|
}
|
||||||
|
|
||||||
/// Verifies that for a given matrix of rooms each room has at least one other room in the
|
/// Verifies that for a given matrix of rooms each room has at least one other room in the
|
||||||
/// same row or column.
|
/// same row or column.
|
||||||
fn rooms_connectable(rooms: &[[Room; ROOMS_HORIZONTAL]; ROOMS_VERTICAL]) -> bool {
|
fn rooms_connectable(rooms: &[[Room; ROOMS_HORIZONTAL]; ROOMS_VERTICAL]) -> bool {
|
||||||
|
@ -191,6 +249,35 @@ impl LevelGenerator {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
//
|
||||||
|
for c in 0..ROOMS_VERTICAL {
|
||||||
|
for r in 0..ROOMS_HORIZONTAL {
|
||||||
|
let src_room = self.rooms[c][r];
|
||||||
|
if let Some(x_conn) = src_room.connection_down {
|
||||||
|
let tgt_room = self.rooms[c][r + x_conn.distance];
|
||||||
|
let top = 1 + r * ROOM_HEIGHT + src_room.offset_y;
|
||||||
|
let left = 1 + c * ROOM_WIDTH + x_conn.offset;
|
||||||
|
let bottom = 1 + (r + x_conn.distance) * ROOM_HEIGHT + tgt_room.offset_y + tgt_room.height;
|
||||||
|
for i in top..bottom {
|
||||||
|
if s[left][i] == LevelElement::Wall {
|
||||||
|
s[left][i] = LevelElement::Floor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if let Some(y_conn) = src_room.connection_right {
|
||||||
|
let tgt_room = self.rooms[c + y_conn.distance][r];
|
||||||
|
|
||||||
|
let top = 1 + r * ROOM_HEIGHT + src_room.offset_y + y_conn.offset - 1;
|
||||||
|
let left = 1 + c * ROOM_WIDTH + src_room.offset_x;
|
||||||
|
let right = 1 + (c + y_conn.distance) * ROOM_WIDTH + tgt_room.offset_x + tgt_room.width;
|
||||||
|
for i in left..right {
|
||||||
|
if s[i][top] == LevelElement::Wall {
|
||||||
|
s[i][top] = LevelElement::Floor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Level {
|
Level {
|
||||||
structure: s,
|
structure: s,
|
||||||
start_x,
|
start_x,
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
use ratatui::prelude::*;
|
use ratatui::prelude::*;
|
||||||
use ratatui::widgets::Widget;
|
use ratatui::widgets::Widget;
|
||||||
|
|
||||||
use crate::game::Game;
|
use crate::game::Game;
|
||||||
use crate::level::{Level, LevelElement};
|
use crate::level::LevelElement;
|
||||||
use crate::player::Player;
|
|
||||||
|
|
||||||
const FG_BROWN: Color = Color::Rgb(186, 74, 0);
|
const FG_BROWN: Color = Color::Rgb(186, 74, 0);
|
||||||
|
|
||||||
|
@ -96,10 +96,10 @@ impl<'a> Widget for LevelWidget<'a> {
|
||||||
self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray);
|
self.set_cell(buf, x, y, " ", FG_BROWN, Color::Gray);
|
||||||
}
|
}
|
||||||
LevelElement::StairDown => {
|
LevelElement::StairDown => {
|
||||||
self.set_cell(buf, x, y, ">", FG_BROWN, Color::Gray);
|
self.set_cell(buf, x, y, ">", Color::Yellow, Color::Gray);
|
||||||
}
|
}
|
||||||
LevelElement::StairUp => {
|
LevelElement::StairUp => {
|
||||||
self.set_cell(buf, x, y, "<", FG_BROWN, Color::Gray);
|
self.set_cell(buf, x, y, "<", Color::Yellow, Color::Gray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use ratatui::prelude::*;
|
||||||
use ratatui::widgets::Block;
|
use ratatui::widgets::Block;
|
||||||
|
|
||||||
use crate::game::Game;
|
use crate::game::Game;
|
||||||
use crate::level::{Level, LevelElement};
|
use crate::level::Level;
|
||||||
use crate::level_widget::LevelWidget;
|
use crate::level_widget::LevelWidget;
|
||||||
use crate::player::Player;
|
use crate::player::Player;
|
||||||
use crate::level_generator::LevelGenerator;
|
use crate::level_generator::LevelGenerator;
|
||||||
|
|
Loading…
Reference in New Issue