WIP. Added simple rooms
This commit is contained in:
parent
ce6a29d899
commit
0e40877eab
|
@ -4,6 +4,7 @@ use mapgen::dungeon::{
|
||||||
MapBuilder,
|
MapBuilder,
|
||||||
map::TileType,
|
map::TileType,
|
||||||
cellular_automata::CellularAutomataGen,
|
cellular_automata::CellularAutomataGen,
|
||||||
|
random_rooms::RandomRoomsGen,
|
||||||
starting_point::{AreaStartingPosition, XStart, YStart},
|
starting_point::{AreaStartingPosition, XStart, YStart},
|
||||||
cull_unreachable::CullUnreachable,
|
cull_unreachable::CullUnreachable,
|
||||||
distant_exit::DistantExit,
|
distant_exit::DistantExit,
|
||||||
|
@ -29,11 +30,24 @@ pub struct World {
|
||||||
impl World {
|
impl World {
|
||||||
pub fn new_cellular_automata(width: u32, height: u32, seed: u32) -> World {
|
pub fn new_cellular_automata(width: u32, height: u32, seed: u32) -> World {
|
||||||
let mut rng = StdRng::seed_from_u64(seed as u64);
|
let mut rng = StdRng::seed_from_u64(seed as u64);
|
||||||
let map = MapBuilder::new(Box::new(CellularAutomataGen::new(width as usize, height as usize)))
|
let map = MapBuilder::new(Box::new(CellularAutomataGen::new()))
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
.with(CullUnreachable::new())
|
.with(CullUnreachable::new())
|
||||||
.with(DistantExit::new())
|
.with(DistantExit::new())
|
||||||
.build_map_with_rng(&mut rng);
|
.build_map_with_rng(width as usize, height as usize, &mut rng);
|
||||||
|
let tiles = (0..map.tiles.len())
|
||||||
|
.map(|i| if map.tiles[i] == TileType::Floor {Cell::Floor} else {Cell::Wall})
|
||||||
|
.collect();
|
||||||
|
World {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
tiles }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_random_rooms(width: u32, height: u32, seed: u32) -> World {
|
||||||
|
let mut rng = StdRng::seed_from_u64(seed as u64);
|
||||||
|
let map = MapBuilder::new(Box::new(RandomRoomsGen::new()))
|
||||||
|
.build_map_with_rng(width as usize, height as usize, &mut rng);
|
||||||
let tiles = (0..map.tiles.len())
|
let tiles = (0..map.tiles.len())
|
||||||
.map(|i| if map.tiles[i] == TileType::Floor {Cell::Floor} else {Cell::Wall})
|
.map(|i| if map.tiles[i] == TileType::Floor {Cell::Floor} else {Cell::Wall})
|
||||||
.collect();
|
.collect();
|
||||||
|
|
|
@ -28,7 +28,10 @@ function newCellularAutomata() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function newSimpleRooms() {
|
function newSimpleRooms() {
|
||||||
console.log("Simple rooms")
|
var seed = Date.now();
|
||||||
|
world = World.new_random_rooms(width, height, seed);
|
||||||
|
requestAnimationFrame(renderLoop);
|
||||||
|
infoDiv.textContent = "Random Rooms with the seed: " + seed;
|
||||||
}
|
}
|
||||||
|
|
||||||
const renderLoop = () => {
|
const renderLoop = () => {
|
||||||
|
|
70
src/common/geometry.rs
Normal file
70
src/common/geometry.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//! Support function for 2D geometry
|
||||||
|
//!
|
||||||
|
|
||||||
|
/// Position on the map
|
||||||
|
#[derive(Default, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||||
|
pub struct Point {
|
||||||
|
pub x: usize,
|
||||||
|
pub y: usize
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Point {
|
||||||
|
/// Create new point
|
||||||
|
pub fn new(x: usize, y: usize) -> Point {
|
||||||
|
Point {x, y}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Euclidean distance to a given point
|
||||||
|
pub fn distance_to(self, point: &Point) -> f32 {
|
||||||
|
let a = (self.x as f32 - point.x as f32).powf(2.0);
|
||||||
|
let b = (self.y as f32 - point.y as f32).powf(2.0);
|
||||||
|
(a + b).sqrt()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Rectangle region on the map
|
||||||
|
#[derive(PartialEq, Copy, Clone)]
|
||||||
|
pub struct Rect {
|
||||||
|
pub x1 : i32,
|
||||||
|
pub x2 : i32,
|
||||||
|
pub y1 : i32,
|
||||||
|
pub y2 : i32
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rect {
|
||||||
|
pub fn new(x:i32, y: i32, width:i32, height:i32) -> Rect {
|
||||||
|
Rect{x1:x, y1:y, x2:x+width, y2:y+height}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if this overlaps with other
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ------------------------------------------------------------------------------------------------
|
||||||
|
/// Module unit tests
|
||||||
|
/// ------------------------------------------------------------------------------------------------
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_distance() {
|
||||||
|
let p1 = Point::new(10, 10);
|
||||||
|
let p2 = Point::new(14, 7);
|
||||||
|
let distance = p1.distance_to(&p2);
|
||||||
|
assert_eq!(distance, 5.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_intersect() {
|
||||||
|
let rect1 = Rect::new(10, 10, 40, 40);
|
||||||
|
let rect2 = Rect::new(30, 30, 60, 60);
|
||||||
|
assert!(rect1.intersect(&rect2));
|
||||||
|
}
|
||||||
|
}
|
2
src/common/mod.rs
Normal file
2
src/common/mod.rs
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
pub mod geometry;
|
||||||
|
pub mod random;
|
29
src/common/random.rs
Normal file
29
src/common/random.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
//! Helper function for random number generator
|
||||||
|
//!
|
||||||
|
use rand::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// Generate random number between start and end inclusive on both ends
|
||||||
|
pub fn random_range(rng: &mut StdRng, start: usize, end: usize) -> usize {
|
||||||
|
let max = (end - start + 1) as u32;
|
||||||
|
((rng.next_u32() % max) + start as u32) as usize
|
||||||
|
}
|
||||||
|
|
||||||
|
/// ------------------------------------------------------------------------------------------------
|
||||||
|
/// Module unit tests
|
||||||
|
/// ------------------------------------------------------------------------------------------------
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
use rand::prelude::*;
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_range() {
|
||||||
|
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||||
|
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
||||||
|
let x = random_range(&mut rng, 5, 8);
|
||||||
|
assert!(x >= 5 && x <= 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,8 +15,8 @@
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let mut rng = StdRng::seed_from_u64(100);
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
//! let gen = CellularAutomataGen::new(80, 50);
|
//! let gen = CellularAutomataGen::new();
|
||||||
//! let map = gen.generate_map(&mut rng);
|
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
//! assert_eq!(map.height, 50);
|
//! assert_eq!(map.height, 50);
|
||||||
|
@ -29,29 +29,26 @@ use super::map::{Map, TileType};
|
||||||
|
|
||||||
|
|
||||||
/// Map generator and modifier
|
/// Map generator and modifier
|
||||||
pub struct CellularAutomataGen {
|
pub struct CellularAutomataGen {}
|
||||||
width: usize,
|
|
||||||
height: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MapGenerator for CellularAutomataGen {
|
impl MapGenerator for CellularAutomataGen {
|
||||||
fn generate_map(&self, rng : &mut StdRng) -> Map {
|
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||||
self.build(rng)
|
self.build(width, height, rng)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellularAutomataGen {
|
impl CellularAutomataGen {
|
||||||
/// Create generator which will create map with the given dimension.
|
/// Create generator which will create map with the given dimension.
|
||||||
pub fn new(width: usize, height: usize) -> CellularAutomataGen {
|
pub fn new() -> CellularAutomataGen {
|
||||||
CellularAutomataGen {width, height}
|
CellularAutomataGen {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate map
|
/// Generate map
|
||||||
fn build(&self, rng : &mut StdRng) -> Map {
|
fn build(&self, width: usize, height: usize, rng: &mut StdRng) -> Map {
|
||||||
let mut map = Map::new(self.width, self.height);
|
let mut map = Map::new(width, height);
|
||||||
// First we completely randomize the map, setting 55% of it to be floor.
|
// First we completely randomize the map, setting 55% of it to be floor.
|
||||||
for y in 1..self.height-1 {
|
for y in 1..height-1 {
|
||||||
for x in 1..self.width-1 {
|
for x in 1..width-1 {
|
||||||
let roll = rng.next_u32() % 100;
|
let roll = rng.next_u32() % 100;
|
||||||
if roll > 55 { map.set_tile(x, y, TileType::Floor) }
|
if roll > 55 { map.set_tile(x, y, TileType::Floor) }
|
||||||
else { map.set_tile(x, y, TileType::Wall) }
|
else { map.set_tile(x, y, TileType::Wall) }
|
||||||
|
|
|
@ -50,7 +50,8 @@ mod tests {
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::MapModifier;
|
use super::MapModifier;
|
||||||
use crate::dungeon::map::{Point, Map};
|
use crate::common::geometry::Point;
|
||||||
|
use crate::dungeon::map::Map;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_culling() {
|
fn test_culling() {
|
||||||
|
|
|
@ -8,9 +8,10 @@
|
||||||
//! Example generator usage:
|
//! Example generator usage:
|
||||||
//! ---
|
//! ---
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
|
//! use crate::common::geometry::Point;
|
||||||
//! use mapgen::dungeon::{
|
//! use mapgen::dungeon::{
|
||||||
//! MapModifier,
|
//! MapModifier,
|
||||||
//! map::{Map, Point, TileType},
|
//! map::{Map, TileType},
|
||||||
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
|
@ -97,7 +98,8 @@ impl DijkstraMap {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::dungeon::map::{Point, Map};
|
use crate::common::geometry::Point;
|
||||||
|
use crate::dungeon::map::Map;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_culling() {
|
fn test_culling() {
|
||||||
|
|
|
@ -6,8 +6,9 @@
|
||||||
|
|
||||||
use std::f32;
|
use std::f32;
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
use super::{MapModifier};
|
use crate::common::geometry::Point;
|
||||||
use super::map::{Map, Point};
|
use super::MapModifier;
|
||||||
|
use super::map::Map;
|
||||||
use super::dijkstra::DijkstraMap;
|
use super::dijkstra::DijkstraMap;
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,7 +54,8 @@ mod tests {
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use super::*;
|
use super::*;
|
||||||
use super::MapModifier;
|
use super::MapModifier;
|
||||||
use crate::dungeon::map::{Point, Map};
|
use crate::common::geometry::Point;
|
||||||
|
use crate::dungeon::map::Map;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_exit() {
|
fn test_exit() {
|
||||||
|
|
|
@ -8,30 +8,9 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
use crate::common::geometry::{Point, Rect};
|
||||||
|
|
||||||
|
|
||||||
/// Position on the map
|
|
||||||
#[derive(Default, PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
|
||||||
pub struct Point {
|
|
||||||
pub x: usize,
|
|
||||||
pub y: usize
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Point {
|
|
||||||
/// Create new point
|
|
||||||
pub fn new(x: usize, y: usize) -> Point {
|
|
||||||
Point {x, y}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Euclidean distance to a given point
|
|
||||||
pub fn distance_to(self, point: &Point) -> f32 {
|
|
||||||
let a = (self.x as f32 - point.x as f32).powf(2.0);
|
|
||||||
let b = (self.y as f32 - point.y as f32).powf(2.0);
|
|
||||||
(a + b).sqrt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Possible tile type on the map
|
|
||||||
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
|
||||||
pub enum TileType {
|
pub enum TileType {
|
||||||
Wall, Floor
|
Wall, Floor
|
||||||
|
@ -123,6 +102,16 @@ impl Map {
|
||||||
self.tiles[idx] = tile;
|
self.tiles[idx] = tile;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create room on the map at given location
|
||||||
|
/// Room is created by setting all tiles in the room to the Floor
|
||||||
|
pub fn create_room(&mut self, rect: &Rect) {
|
||||||
|
for x in rect.x1..rect.x2 {
|
||||||
|
for y in rect.y1..rect.y2 {
|
||||||
|
self.set_tile(x as usize, y as usize, TileType::Floor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Map {
|
impl fmt::Display for Map {
|
||||||
|
@ -145,14 +134,6 @@ impl fmt::Display for Map {
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_distance() {
|
|
||||||
let p1 = Point::new(10, 10);
|
|
||||||
let p2 = Point::new(14, 7);
|
|
||||||
let distance = p1.distance_to(&p2);
|
|
||||||
assert_eq!(distance, 5.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_new_map() {
|
fn test_new_map() {
|
||||||
let map = Map::new(10, 10);
|
let map = Map::new(10, 10);
|
||||||
|
@ -198,4 +179,20 @@ mod tests {
|
||||||
let expected_exists = vec![(2, 1, 1.0), (1, 2, 1.0), (2, 2, 1.45)];
|
let expected_exists = vec![(2, 1, 1.0), (1, 2, 1.0), (2, 2, 1.45)];
|
||||||
assert_eq!(exists, expected_exists);
|
assert_eq!(exists, expected_exists);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_create_room() {
|
||||||
|
let mut map = Map::new(5, 5);
|
||||||
|
map.create_room(&Rect::new(1, 1, 3, 3));
|
||||||
|
for x in 0..map.width {
|
||||||
|
for y in 0..map.height {
|
||||||
|
if x == 0 || y == 0 || x == 4 || y == 4 {
|
||||||
|
assert_eq!(map.at(x, y), TileType::Wall);
|
||||||
|
} else {
|
||||||
|
assert_eq!(map.at(x, y), TileType::Floor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -8,16 +8,17 @@
|
||||||
//!
|
//!
|
||||||
//! Example
|
//! Example
|
||||||
//! ```
|
//! ```
|
||||||
|
//! use mapgen::common::geometry::Point;
|
||||||
//! use mapgen::dungeon::{
|
//! use mapgen::dungeon::{
|
||||||
//! MapBuilder,
|
//! MapBuilder,
|
||||||
//! map::{Map, Point, TileType},
|
//! map::{Map, TileType},
|
||||||
//! cellular_automata::CellularAutomataGen,
|
//! cellular_automata::CellularAutomataGen,
|
||||||
//! starting_point::{AreaStartingPosition, XStart, YStart},
|
//! starting_point::{AreaStartingPosition, XStart, YStart},
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
//! let map = MapBuilder::new(Box::new(CellularAutomataGen::new(80, 50)))
|
//! let map = MapBuilder::new(Box::new(CellularAutomataGen::new()))
|
||||||
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
//! .build_map();
|
//! .build_map(80, 50);
|
||||||
//!
|
//!
|
||||||
//! assert_eq!(map.width, 80);
|
//! assert_eq!(map.width, 80);
|
||||||
//! assert_eq!(map.height, 50);
|
//! assert_eq!(map.height, 50);
|
||||||
|
@ -29,6 +30,7 @@ pub mod map;
|
||||||
pub mod cellular_automata;
|
pub mod cellular_automata;
|
||||||
pub mod cull_unreachable;
|
pub mod cull_unreachable;
|
||||||
pub mod distant_exit;
|
pub mod distant_exit;
|
||||||
|
pub mod random_rooms;
|
||||||
pub mod starting_point;
|
pub mod starting_point;
|
||||||
mod dijkstra;
|
mod dijkstra;
|
||||||
|
|
||||||
|
@ -40,7 +42,7 @@ use map::Map;
|
||||||
/// Trait which should be implemented by any map generator which want to be used
|
/// Trait which should be implemented by any map generator which want to be used
|
||||||
/// by MapBuilder
|
/// by MapBuilder
|
||||||
pub trait MapGenerator {
|
pub trait MapGenerator {
|
||||||
fn generate_map(&self, rng: &mut StdRng) -> Map;
|
fn generate_map(&self, width: usize, height: usize, rng: &mut StdRng) -> Map;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait which should be implemented by map modifier.
|
/// Trait which should be implemented by map modifier.
|
||||||
|
@ -70,15 +72,15 @@ impl MapBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build map using random number seeded with system time
|
/// Build map using random number seeded with system time
|
||||||
pub fn build_map(&mut self) -> Map {
|
pub fn build_map(&mut self, width: usize, height: usize) -> Map {
|
||||||
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
let system_time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Can't access system time");
|
||||||
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
let mut rng = StdRng::seed_from_u64(system_time.as_millis() as u64);
|
||||||
self.build_map_with_rng(&mut rng)
|
self.build_map_with_rng(width, height, &mut rng)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build map using provided random number generator
|
/// Build map using provided random number generator
|
||||||
pub fn build_map_with_rng(&mut self, rng: &mut StdRng) -> Map {
|
pub fn build_map_with_rng(&mut self, width: usize, height: usize, rng: &mut StdRng) -> Map {
|
||||||
let mut map = self.generator.generate_map(rng);
|
let mut map = self.generator.generate_map(width, height, rng);
|
||||||
|
|
||||||
// Build additional layers in turn
|
// Build additional layers in turn
|
||||||
for modifier in self.modifiers.iter() {
|
for modifier in self.modifiers.iter() {
|
||||||
|
@ -101,9 +103,9 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ca_map() {
|
fn test_ca_map() {
|
||||||
let map = MapBuilder::new(Box::new(CellularAutomataGen::new(80, 50)))
|
let map = MapBuilder::new(Box::new(CellularAutomataGen::new()))
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
.build_map();
|
.build_map(80, 50);
|
||||||
|
|
||||||
assert_eq!(map.width, 80);
|
assert_eq!(map.width, 80);
|
||||||
assert_eq!(map.height, 50);
|
assert_eq!(map.height, 50);
|
||||||
|
|
75
src/dungeon/random_rooms.rs
Normal file
75
src/dungeon/random_rooms.rs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//! Random rooms map generator.
|
||||||
|
//!
|
||||||
|
//! Try to generate rooms of different size to fille the whole map area.
|
||||||
|
//!
|
||||||
|
//! Example generator usage:
|
||||||
|
//! ```
|
||||||
|
//! use rand::prelude::*;
|
||||||
|
//! use mapgen::dungeon::{
|
||||||
|
//! MapGenerator,
|
||||||
|
//! random_rooms::RandomRoomsGen
|
||||||
|
//! };
|
||||||
|
//!
|
||||||
|
//! let mut rng = StdRng::seed_from_u64(100);
|
||||||
|
//! let gen = RandomRoomsGen::new();
|
||||||
|
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||||
|
//!
|
||||||
|
//! assert_eq!(map.width, 80);
|
||||||
|
//! assert_eq!(map.height, 50);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
|
||||||
|
use rand::prelude::*;
|
||||||
|
use super::MapGenerator;
|
||||||
|
use crate::common::geometry::Rect;
|
||||||
|
use crate::common::random;
|
||||||
|
use super::map::{Map};
|
||||||
|
|
||||||
|
|
||||||
|
pub struct RandomRoomsGen {
|
||||||
|
max_rooms: usize,
|
||||||
|
min_room_size: usize,
|
||||||
|
max_room_size: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MapGenerator for RandomRoomsGen {
|
||||||
|
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||||
|
self.build_rooms(width, height, rng)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl RandomRoomsGen {
|
||||||
|
pub fn new() -> RandomRoomsGen {
|
||||||
|
RandomRoomsGen{
|
||||||
|
max_rooms: 30,
|
||||||
|
min_room_size: 6,
|
||||||
|
max_room_size: 10
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn build_rooms(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||||
|
let mut map = Map::new(width, height);
|
||||||
|
let mut rooms : Vec<Rect> = Vec::new();
|
||||||
|
|
||||||
|
// Create room dimensions
|
||||||
|
for _ in 0..self.max_rooms {
|
||||||
|
let w = random::random_range(rng, self.min_room_size, self.max_room_size);
|
||||||
|
let h = random::random_range(rng, self.min_room_size, self.max_room_size);
|
||||||
|
let x = random::random_range(rng, 0, width - w);
|
||||||
|
let y = random::random_range(rng, 0, height - h);
|
||||||
|
let new_room = Rect::new(x as i32, y as i32, w as i32, h as i32);
|
||||||
|
let intersects = rooms.iter().any(|r| new_room.intersect(r));
|
||||||
|
if !intersects {
|
||||||
|
rooms.push(new_room);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply rooms to the map
|
||||||
|
for room in rooms {
|
||||||
|
map.create_room(&room);
|
||||||
|
}
|
||||||
|
|
||||||
|
map
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,9 +6,10 @@
|
||||||
//! Example modifier usage:
|
//! Example modifier usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
|
//! use mapgen::common::geometry::Point;
|
||||||
//! use mapgen::dungeon::{
|
//! use mapgen::dungeon::{
|
||||||
//! MapModifier,
|
//! MapModifier,
|
||||||
//! map::{Map, Point, TileType},
|
//! map::{Map, TileType},
|
||||||
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
|
@ -24,7 +25,8 @@
|
||||||
|
|
||||||
use rand::prelude::StdRng;
|
use rand::prelude::StdRng;
|
||||||
use super::{MapModifier};
|
use super::{MapModifier};
|
||||||
use super::map::{Map, Point, TileType};
|
use crate::common::geometry::Point;
|
||||||
|
use super::map::{Map, TileType};
|
||||||
|
|
||||||
|
|
||||||
/// Initial x region position
|
/// Initial x region position
|
||||||
|
|
|
@ -4,4 +4,5 @@
|
||||||
//! * Dungeon maps
|
//! * Dungeon maps
|
||||||
//!
|
//!
|
||||||
|
|
||||||
|
pub mod common;
|
||||||
pub mod dungeon;
|
pub mod dungeon;
|
Loading…
Reference in New Issue
Block a user