refactoring API
This commit is contained in:
parent
a75f565cbb
commit
278b549094
|
@ -6,14 +6,14 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::map_builder::{
|
||||
//! MapGenerator,
|
||||
//! bsp_interior::BspInteriorGen
|
||||
//! use mapgen::{Map, MapFilter};
|
||||
//! use mapgen::filter::{
|
||||
//! BspInterior
|
||||
//! };
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = BspInteriorGen::new();
|
||||
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||
//! let gen = BspInterior::new();
|
||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
//!
|
||||
//! assert_eq!(map.width, 80);
|
||||
//! assert_eq!(map.height, 50);
|
||||
|
@ -21,34 +21,34 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::*;
|
||||
use super::MapGenerator;
|
||||
use super::MapFilter;
|
||||
use crate::geometry::{Point, Rect};
|
||||
use crate::random::Rng;
|
||||
use crate::map::Map;
|
||||
|
||||
|
||||
pub struct BspInteriorGen {
|
||||
pub struct BspInterior {
|
||||
min_room_size: usize,
|
||||
}
|
||||
|
||||
impl MapGenerator for BspInteriorGen {
|
||||
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||
self.build(rng, width, height)
|
||||
impl MapFilter for BspInterior {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(rng, map)
|
||||
}
|
||||
}
|
||||
|
||||
impl BspInteriorGen {
|
||||
impl BspInterior {
|
||||
|
||||
pub fn new() -> Box<BspInteriorGen> {
|
||||
Box::new(BspInteriorGen{
|
||||
pub fn new() -> Box<BspInterior> {
|
||||
Box::new(BspInterior{
|
||||
min_room_size: 8,
|
||||
})
|
||||
}
|
||||
|
||||
fn build(&self, rng: &mut StdRng, width: usize, height: usize) -> Map {
|
||||
let mut map = Map::new(width, height);
|
||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
let mut rects: Vec<Rect> = Vec::new();
|
||||
rects.push( Rect::new(1, 1, map.width-2, map.height-2) );
|
||||
rects.push( Rect::new(1, 1, new_map.width-2, new_map.height-2) );
|
||||
let first_room = rects[0];
|
||||
// Divide the first room
|
||||
self.add_subrects(first_room, rng, &mut rects);
|
||||
|
@ -56,21 +56,21 @@ impl BspInteriorGen {
|
|||
let rooms_copy = rects.clone();
|
||||
for r in rooms_copy.iter() {
|
||||
let room = *r;
|
||||
map.add_room(room);
|
||||
new_map.add_room(room);
|
||||
}
|
||||
|
||||
// Now we want corridors
|
||||
for i in 0..map.rooms.len()-1 {
|
||||
let room = map.rooms[i];
|
||||
let next_room = map.rooms[i+1];
|
||||
for i in 0..new_map.rooms.len()-1 {
|
||||
let room = new_map.rooms[i];
|
||||
let next_room = new_map.rooms[i+1];
|
||||
let start_x = room.x1 + rng.random_range(1, room.width());
|
||||
let start_y = room.y1 + rng.random_range(1, room.height());
|
||||
let end_x = next_room.x1 + (rng.random_range(1, next_room.width()));
|
||||
let end_y = next_room.y1 + (rng.random_range(1, next_room.width()));
|
||||
map.add_corridor(Point::new(start_x, start_y), Point::new(end_x, end_y));
|
||||
new_map.add_corridor(Point::new(start_x, start_y), Point::new(end_x, end_y));
|
||||
}
|
||||
|
||||
map
|
||||
new_map
|
||||
}
|
||||
|
||||
fn add_subrects(&self, rect: Rect, rng: &mut StdRng, rects: &mut Vec<Rect>) {
|
|
@ -6,14 +6,12 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::map_builder::{
|
||||
//! MapGenerator,
|
||||
//! bsp_rooms::BspRoomsGen
|
||||
//! };
|
||||
//! use mapgen::{Map, MapFilter};
|
||||
//! use mapgen::filter::BspRooms;
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = BspRoomsGen::new();
|
||||
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||
//! let gen = BspRooms::new();
|
||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
//!
|
||||
//! assert_eq!(map.width, 80);
|
||||
//! assert_eq!(map.height, 50);
|
||||
|
@ -21,34 +19,34 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::*;
|
||||
use super::MapGenerator;
|
||||
use super::MapFilter;
|
||||
use crate::geometry::Rect;
|
||||
use crate::random::Rng;
|
||||
use crate::map::{Map, TileType};
|
||||
|
||||
|
||||
pub struct BspRoomsGen {
|
||||
pub struct BspRooms {
|
||||
max_split: usize,
|
||||
}
|
||||
|
||||
impl MapGenerator for BspRoomsGen {
|
||||
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||
self.build_rooms(width, height, rng)
|
||||
impl MapFilter for BspRooms {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
self.build_rooms(map, rng)
|
||||
}
|
||||
}
|
||||
|
||||
impl BspRoomsGen {
|
||||
pub fn new() -> Box<BspRoomsGen> {
|
||||
Box::new(BspRoomsGen {
|
||||
impl BspRooms {
|
||||
pub fn new() -> Box<BspRooms> {
|
||||
Box::new(BspRooms {
|
||||
max_split: 240,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_rooms(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||
let mut map = Map::new(width, height);
|
||||
fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
let mut rects: Vec<Rect> = Vec::new();
|
||||
// Start with a single map-sized rectangle
|
||||
rects.push( Rect::new(2, 2, width-5, height-5) );
|
||||
rects.push( Rect::new(2, 2, new_map.width-5, new_map.height-5) );
|
||||
let first_room = rects[0];
|
||||
rects.append(&mut self.split_into_subrects(first_room)); // Divide the first room
|
||||
|
||||
|
@ -59,14 +57,14 @@ impl BspRoomsGen {
|
|||
let rect = self.get_random_rect(rng, &rects);
|
||||
let candidate = self.get_random_sub_rect(rect, rng);
|
||||
|
||||
if self.is_possible(candidate, &map) {
|
||||
map.add_room(candidate);
|
||||
if self.is_possible(candidate, &new_map) {
|
||||
new_map.add_room(candidate);
|
||||
rects.append(&mut self.split_into_subrects(rect));
|
||||
}
|
||||
n_rooms += 1;
|
||||
}
|
||||
|
||||
map
|
||||
new_map
|
||||
}
|
||||
|
||||
fn split_into_subrects(&self, rect: Rect) -> Vec<Rect> {
|
|
@ -9,14 +9,12 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::map_builder::{
|
||||
//! MapGenerator,
|
||||
//! cellular_automata::CellularAutomataGen
|
||||
//! };
|
||||
//! use mapgen::{Map, MapFilter};
|
||||
//! use mapgen::filter::CellularAutomata;
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = CellularAutomataGen::new();
|
||||
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||
//! let gen = CellularAutomata::new();
|
||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
//!
|
||||
//! assert_eq!(map.width, 80);
|
||||
//! assert_eq!(map.height, 50);
|
||||
|
@ -24,54 +22,47 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::*;
|
||||
use super::{MapGenerator, MapModifier};
|
||||
use super::MapFilter;
|
||||
use crate::map::{Map, TileType};
|
||||
|
||||
|
||||
/// Map generator and modifier
|
||||
pub struct CellularAutomataGen {}
|
||||
pub struct CellularAutomata {}
|
||||
|
||||
impl MapGenerator for CellularAutomataGen {
|
||||
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||
self.build(width, height, rng)
|
||||
impl MapFilter for CellularAutomata {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(map, rng)
|
||||
}
|
||||
}
|
||||
|
||||
impl CellularAutomataGen {
|
||||
impl CellularAutomata {
|
||||
/// Create generator which will create map with the given dimension.
|
||||
pub fn new() -> Box<CellularAutomataGen> {
|
||||
Box::new(CellularAutomataGen {})
|
||||
pub fn new() -> Box<CellularAutomata> {
|
||||
Box::new(CellularAutomata {})
|
||||
}
|
||||
|
||||
/// Generate map
|
||||
fn build(&self, width: usize, height: usize, rng: &mut StdRng) -> Map {
|
||||
let mut map = Map::new(width, height);
|
||||
fn build(&self, map: &Map, rng: &mut StdRng) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
// First we completely randomize the map, setting 55% of it to be floor.
|
||||
for y in 1..height-1 {
|
||||
for x in 1..width-1 {
|
||||
for y in 1..new_map.height-1 {
|
||||
for x in 1..new_map.width-1 {
|
||||
let roll = rng.next_u32() % 100;
|
||||
if roll > 55 { map.set_tile(x, y, TileType::Floor) }
|
||||
else { map.set_tile(x, y, TileType::Wall) }
|
||||
if roll > 55 { new_map.set_tile(x, y, TileType::Floor) }
|
||||
else { new_map.set_tile(x, y, TileType::Wall) }
|
||||
}
|
||||
}
|
||||
|
||||
// Now we iteratively apply cellular automata rules
|
||||
for _ in 0..15 {
|
||||
map = apply_iteration(&map);
|
||||
new_map = apply_iteration(&new_map);
|
||||
}
|
||||
|
||||
map
|
||||
new_map
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl MapModifier for CellularAutomataGen {
|
||||
fn modify_map(&self, _rng: &mut StdRng, map : &Map) -> Map {
|
||||
apply_iteration(map)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fn apply_iteration(map: &Map) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
|
|
@ -5,7 +5,7 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::StdRng;
|
||||
use super::MapModifier;
|
||||
use super::MapFilter;
|
||||
use crate::map::{Map, TileType};
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
|
||||
|
@ -13,7 +13,7 @@ use crate::dijkstra::DijkstraMap;
|
|||
/// Remove unreachable areas from the map.
|
||||
pub struct CullUnreachable {}
|
||||
|
||||
impl MapModifier for CullUnreachable {
|
||||
impl MapFilter for CullUnreachable {
|
||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(map)
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ impl CullUnreachable {
|
|||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::*;
|
||||
use super::MapModifier;
|
||||
use super::MapFilter;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::Map;
|
||||
|
|
@ -7,7 +7,7 @@
|
|||
use std::f32;
|
||||
use rand::prelude::StdRng;
|
||||
use crate::geometry::Point;
|
||||
use super::MapModifier;
|
||||
use super::MapFilter;
|
||||
use crate::map::Map;
|
||||
use crate::dijkstra::DijkstraMap;
|
||||
|
||||
|
@ -15,7 +15,7 @@ use crate::dijkstra::DijkstraMap;
|
|||
/// Add exist position to the map based on the distance from the start point.
|
||||
pub struct DistantExit {}
|
||||
|
||||
impl MapModifier for DistantExit {
|
||||
impl MapFilter for DistantExit {
|
||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(map)
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ impl DistantExit {
|
|||
mod tests {
|
||||
use rand::prelude::*;
|
||||
use super::*;
|
||||
use super::MapModifier;
|
||||
use super::MapFilter;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::Map;
|
||||
|
130
src/filter/drunkard.rs
Normal file
130
src/filter/drunkard.rs
Normal file
|
@ -0,0 +1,130 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::{Map, MapFilter};
|
||||
//! use mapgen::filter::DrunkardsWalk;
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = DrunkardsWalk::open_area();
|
||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
//!
|
||||
//! assert_eq!(map.width, 80);
|
||||
//! assert_eq!(map.height, 50);
|
||||
//! ```
|
||||
//!
|
||||
|
||||
use rand::prelude::*;
|
||||
use super::MapFilter;
|
||||
use crate::{
|
||||
map::{Map, Symmetry, TileType},
|
||||
geometry::Point,
|
||||
random::Rng
|
||||
};
|
||||
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum DrunkSpawnMode { StartingPoint, Random }
|
||||
|
||||
pub struct DrunkardsWalk {
|
||||
spawn_mode : DrunkSpawnMode,
|
||||
drunken_lifetime : i32,
|
||||
floor_percent: f32,
|
||||
brush_size: usize,
|
||||
symmetry: Symmetry
|
||||
}
|
||||
|
||||
impl MapFilter for DrunkardsWalk {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(rng, map)
|
||||
}
|
||||
}
|
||||
|
||||
impl DrunkardsWalk {
|
||||
pub fn new( spawn_mode: DrunkSpawnMode,
|
||||
drunken_lifetime: i32,
|
||||
floor_percent: f32,
|
||||
brush_size: usize,
|
||||
symmetry: Symmetry) -> Box<DrunkardsWalk>
|
||||
{
|
||||
Box::new(DrunkardsWalk{
|
||||
spawn_mode,
|
||||
drunken_lifetime,
|
||||
floor_percent,
|
||||
brush_size,
|
||||
symmetry
|
||||
})
|
||||
}
|
||||
|
||||
pub fn open_area() -> Box<DrunkardsWalk> {
|
||||
Self::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn open_halls() -> Box<DrunkardsWalk> {
|
||||
Self::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn winding_passages() -> Box<DrunkardsWalk> {
|
||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn fat_passages() -> Box<DrunkardsWalk> {
|
||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn fearful_symmetry() -> Box<DrunkardsWalk> {
|
||||
Self::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both)
|
||||
}
|
||||
|
||||
fn build(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
// Set a central starting point
|
||||
let starting_position = Point::new( new_map.width / 2, new_map.height / 2 );
|
||||
new_map.set_tile(starting_position.x, starting_position.y, TileType::Floor);
|
||||
|
||||
let total_tiles = new_map.width * new_map.height;
|
||||
let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize;
|
||||
let mut floor_tile_count = new_map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
||||
let mut digger_count = 0;
|
||||
while floor_tile_count < desired_floor_tiles {
|
||||
let mut drunk_x;
|
||||
let mut drunk_y;
|
||||
match self.spawn_mode {
|
||||
DrunkSpawnMode::StartingPoint => {
|
||||
drunk_x = starting_position.x;
|
||||
drunk_y = starting_position.y;
|
||||
}
|
||||
DrunkSpawnMode::Random => {
|
||||
if digger_count == 0 {
|
||||
drunk_x = starting_position.x;
|
||||
drunk_y = starting_position.y;
|
||||
} else {
|
||||
drunk_x = rng.roll_dice(1, new_map.width - 3) + 1;
|
||||
drunk_y = rng.roll_dice(1, new_map.height - 3) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut drunk_life = self.drunken_lifetime;
|
||||
|
||||
while drunk_life > 0 {
|
||||
new_map.set_tile(drunk_x, drunk_y, TileType::Wall);
|
||||
new_map.paint(self.symmetry, self.brush_size, drunk_x, drunk_y);
|
||||
// map.exit_point = Some(Point::new(drunk_x, drunk_y));
|
||||
|
||||
let stagger_direction = rng.roll_dice(1, 4);
|
||||
match stagger_direction {
|
||||
1 => { if drunk_x > 2 { drunk_x -= 1; } }
|
||||
2 => { if drunk_x < new_map.width-2 { drunk_x += 1; } }
|
||||
3 => { if drunk_y > 2 { drunk_y -=1; } }
|
||||
_ => { if drunk_y < new_map.height-2 { drunk_y += 1; } }
|
||||
}
|
||||
|
||||
drunk_life -= 1;
|
||||
}
|
||||
|
||||
digger_count += 1;
|
||||
floor_tile_count = new_map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
||||
}
|
||||
|
||||
new_map
|
||||
}
|
||||
}
|
|
@ -8,17 +8,15 @@
|
|||
//!
|
||||
//! Example
|
||||
//! ```
|
||||
//! use mapgen::{
|
||||
//! map_builder::{
|
||||
//! MapModifier, MapBuilder,
|
||||
//! cellular_automata::CellularAutomataGen,
|
||||
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
|
||||
//! use mapgen::filter::{
|
||||
//! CellularAutomata,
|
||||
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
||||
//! },
|
||||
//! map::{Map, TileType},
|
||||
//! geometry::Point,
|
||||
//! };
|
||||
//! use mapgen::geometry::Point;
|
||||
//!
|
||||
//! let map = MapBuilder::new(CellularAutomataGen::new())
|
||||
//! let map = MapBuilder::new()
|
||||
//! .with(CellularAutomata::new())
|
||||
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||
//! .build_map(80, 50);
|
||||
//!
|
||||
|
@ -38,39 +36,41 @@ pub mod simple_rooms;
|
|||
pub mod rooms_corridors_nearest;
|
||||
pub mod starting_point;
|
||||
|
||||
pub use bsp_interior::BspInterior;
|
||||
pub use bsp_rooms::BspRooms;
|
||||
pub use cellular_automata::CellularAutomata;
|
||||
pub use cull_unreachable::CullUnreachable;
|
||||
pub use distant_exit::DistantExit;
|
||||
pub use drunkard::DrunkardsWalk;
|
||||
pub use simple_rooms::SimpleRooms;
|
||||
pub use rooms_corridors_nearest::NearestCorridors;
|
||||
pub use starting_point::AreaStartingPosition;
|
||||
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use rand::prelude::*;
|
||||
use crate::map::Map;
|
||||
|
||||
|
||||
/// Trait which should be implemented by any map generator which want to be used
|
||||
/// by MapBuilder
|
||||
pub trait MapGenerator {
|
||||
fn generate_map(&self, width: usize, height: usize, rng: &mut StdRng) -> Map;
|
||||
}
|
||||
|
||||
/// Trait which should be implemented by map modifier.
|
||||
/// Modifier takes initiall map and apply changes to it.
|
||||
pub trait MapModifier {
|
||||
pub trait MapFilter {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map;
|
||||
}
|
||||
|
||||
/// Used to chain MapBuilder and MapModifiers to create the final map.
|
||||
pub struct MapBuilder {
|
||||
generator: Box<dyn MapGenerator>,
|
||||
modifiers: Vec<Box<dyn MapModifier>>,
|
||||
modifiers: Vec<Box<dyn MapFilter>>,
|
||||
}
|
||||
|
||||
impl MapBuilder {
|
||||
/// Create Map Builder with initial map generator
|
||||
pub fn new(generator : Box<dyn MapGenerator>) -> MapBuilder {
|
||||
pub fn new() -> MapBuilder {
|
||||
MapBuilder {
|
||||
generator,
|
||||
modifiers: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with(&mut self, modifier : Box<dyn MapModifier>) -> &mut MapBuilder {
|
||||
pub fn with(&mut self, modifier : Box<dyn MapFilter>) -> &mut MapBuilder {
|
||||
self.modifiers.push(modifier);
|
||||
self
|
||||
}
|
||||
|
@ -84,7 +84,7 @@ impl MapBuilder {
|
|||
|
||||
/// Build map using provided random number generator
|
||||
pub fn build_map_with_rng(&mut self, width: usize, height: usize, rng: &mut StdRng) -> Map {
|
||||
let mut map = self.generator.generate_map(width, height, rng);
|
||||
let mut map = Map::new(width, height);
|
||||
|
||||
// Build additional layers in turn
|
||||
for modifier in self.modifiers.iter() {
|
||||
|
@ -102,12 +102,13 @@ impl MapBuilder {
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use cellular_automata::CellularAutomataGen;
|
||||
use cellular_automata::CellularAutomata;
|
||||
use starting_point::{AreaStartingPosition, XStart, YStart};
|
||||
|
||||
#[test]
|
||||
fn test_ca_map() {
|
||||
let map = MapBuilder::new(CellularAutomataGen::new())
|
||||
let map = MapBuilder::new()
|
||||
.with(CellularAutomata::new())
|
||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||
.build_map(80, 50);
|
||||
|
|
@ -1,14 +1,14 @@
|
|||
//! Connect nearest rooms on the map with corridors
|
||||
//!
|
||||
use rand::prelude::StdRng;
|
||||
use super::MapModifier;
|
||||
use super::MapFilter;
|
||||
use crate::map::Map;
|
||||
use std::collections::HashSet;
|
||||
|
||||
|
||||
pub struct NearestCorridors {}
|
||||
|
||||
impl MapModifier for NearestCorridors {
|
||||
impl MapFilter for NearestCorridors {
|
||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
||||
self.corridors(map)
|
||||
}
|
|
@ -6,14 +6,12 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::map_builder::{
|
||||
//! MapGenerator,
|
||||
//! simple_rooms::SimpleRoomsGen
|
||||
//! };
|
||||
//! use mapgen::{MapFilter, Map};
|
||||
//! use mapgen::filter::SimpleRooms;
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = SimpleRoomsGen::new();
|
||||
//! let map = gen.generate_map(80, 50, &mut rng);
|
||||
//! let gen = SimpleRooms::new();
|
||||
//! let map = gen.modify_map(&mut rng, &Map::new(80, 50));
|
||||
//!
|
||||
//! assert_eq!(map.width, 80);
|
||||
//! assert_eq!(map.height, 50);
|
||||
|
@ -21,50 +19,50 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::*;
|
||||
use super::MapGenerator;
|
||||
use super::MapFilter;
|
||||
use crate::geometry::Rect;
|
||||
use crate::random::Rng;
|
||||
use crate::map::{Map};
|
||||
|
||||
|
||||
pub struct SimpleRoomsGen {
|
||||
pub struct SimpleRooms {
|
||||
max_rooms: usize,
|
||||
min_room_size: usize,
|
||||
max_room_size: usize,
|
||||
}
|
||||
|
||||
impl MapGenerator for SimpleRoomsGen {
|
||||
fn generate_map(&self, width: usize, height: usize, rng : &mut StdRng) -> Map {
|
||||
self.build_rooms(width, height, rng)
|
||||
impl MapFilter for SimpleRooms {
|
||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
||||
self.build_rooms(map, rng)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl SimpleRoomsGen {
|
||||
pub fn new() -> Box<SimpleRoomsGen> {
|
||||
Box::new(SimpleRoomsGen{
|
||||
impl SimpleRooms {
|
||||
pub fn new() -> Box<SimpleRooms> {
|
||||
Box::new(SimpleRooms{
|
||||
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);
|
||||
fn build_rooms(&self, map: &Map, rng : &mut StdRng) -> Map {
|
||||
let mut new_map = map.clone();
|
||||
|
||||
// Create room dimensions
|
||||
for _ in 0..self.max_rooms {
|
||||
let w = rng.random_range(self.min_room_size, self.max_room_size);
|
||||
let h = rng.random_range(self.min_room_size, self.max_room_size);
|
||||
let x = rng.random_range(1, width - w);
|
||||
let y = rng.random_range(1, height - h);
|
||||
let x = rng.random_range(1, new_map.width - w);
|
||||
let y = rng.random_range(1, new_map.height - h);
|
||||
let new_room = Rect::new(x, y, w, h);
|
||||
let intersects = map.rooms.iter().any(|r| new_room.intersect(r));
|
||||
let intersects = new_map.rooms.iter().any(|r| new_room.intersect(r));
|
||||
if !intersects {
|
||||
map.add_room(new_room);
|
||||
new_map.add_room(new_room);
|
||||
}
|
||||
}
|
||||
|
||||
map
|
||||
new_map
|
||||
}
|
||||
}
|
|
@ -6,14 +6,9 @@
|
|||
//! Example modifier usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::{
|
||||
//! map_builder::{
|
||||
//! MapModifier,
|
||||
//! starting_point::{AreaStartingPosition, XStart, YStart},
|
||||
//! },
|
||||
//! map::{Map, TileType},
|
||||
//! geometry::Point,
|
||||
//! };
|
||||
//! use mapgen::{MapFilter, Map, TileType};
|
||||
//! use mapgen::filter::starting_point::{AreaStartingPosition, XStart, YStart};
|
||||
//! use mapgen::geometry::Point;
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let mut map = Map::new(80, 50);
|
||||
|
@ -26,7 +21,7 @@
|
|||
//!
|
||||
|
||||
use rand::prelude::StdRng;
|
||||
use super::{MapModifier};
|
||||
use super::MapFilter;
|
||||
use crate::geometry::Point;
|
||||
use crate::map::{Map, TileType};
|
||||
|
||||
|
@ -43,7 +38,7 @@ pub struct AreaStartingPosition {
|
|||
y : YStart
|
||||
}
|
||||
|
||||
impl MapModifier for AreaStartingPosition {
|
||||
impl MapFilter for AreaStartingPosition {
|
||||
fn modify_map(&self, _: &mut StdRng, map: &Map) -> Map {
|
||||
self.build(map)
|
||||
}
|
|
@ -4,9 +4,12 @@
|
|||
//! * Dungeon maps
|
||||
//!
|
||||
|
||||
pub mod map_builder;
|
||||
pub mod filter;
|
||||
pub mod geometry;
|
||||
pub mod map;
|
||||
|
||||
pub use map::{Map, TileType};
|
||||
pub use filter::{MapFilter, MapBuilder};
|
||||
|
||||
pub (crate) mod dijkstra;
|
||||
pub (crate) mod random;
|
|
@ -1,137 +0,0 @@
|
|||
//! Example generator usage:
|
||||
//! ```
|
||||
//! use rand::prelude::*;
|
||||
//! use mapgen::map_builder::{
|
||||
//! MapGenerator,
|
||||
//! drunkard::DrunkardsWalkGen
|
||||
//! };
|
||||
//!
|
||||
//! let mut rng = StdRng::seed_from_u64(100);
|
||||
//! let gen = DrunkardsWalkGen::open_area();
|
||||
//! 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::{
|
||||
map::{Map, Symmetry, TileType},
|
||||
geometry::Point,
|
||||
random::Rng
|
||||
};
|
||||
|
||||
|
||||
#[derive(PartialEq, Copy, Clone)]
|
||||
pub enum DrunkSpawnMode { StartingPoint, Random }
|
||||
|
||||
pub struct DrunkardsWalkGen {
|
||||
spawn_mode : DrunkSpawnMode,
|
||||
drunken_lifetime : i32,
|
||||
floor_percent: f32,
|
||||
brush_size: usize,
|
||||
symmetry: Symmetry
|
||||
}
|
||||
|
||||
impl MapGenerator for DrunkardsWalkGen {
|
||||
fn generate_map(&self, width: usize, height: usize, rng: &mut StdRng) -> Map {
|
||||
self.build(rng, width, height)
|
||||
}
|
||||
}
|
||||
|
||||
impl DrunkardsWalkGen {
|
||||
pub fn new( spawn_mode: DrunkSpawnMode,
|
||||
drunken_lifetime: i32,
|
||||
floor_percent: f32,
|
||||
brush_size: usize,
|
||||
symmetry: Symmetry) -> Box<DrunkardsWalkGen>
|
||||
{
|
||||
Box::new(DrunkardsWalkGen{
|
||||
spawn_mode,
|
||||
drunken_lifetime,
|
||||
floor_percent,
|
||||
brush_size,
|
||||
symmetry
|
||||
})
|
||||
}
|
||||
|
||||
pub fn open_area() -> Box<DrunkardsWalkGen> {
|
||||
DrunkardsWalkGen::new(DrunkSpawnMode::StartingPoint, 400, 0.5, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn open_halls() -> Box<DrunkardsWalkGen> {
|
||||
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.5, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn winding_passages() -> Box<DrunkardsWalkGen> {
|
||||
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn fat_passages() -> Box<DrunkardsWalkGen> {
|
||||
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 2, Symmetry::None)
|
||||
}
|
||||
|
||||
pub fn fearful_symmetry() -> Box<DrunkardsWalkGen> {
|
||||
DrunkardsWalkGen::new(DrunkSpawnMode::Random, 400, 0.4, 1, Symmetry::Both)
|
||||
}
|
||||
|
||||
fn build(&self, rng: &mut StdRng, width: usize, height: usize) -> Map {
|
||||
let mut map = Map::new(width, height);
|
||||
// Set a central starting point
|
||||
let starting_position = Point::new( map.width / 2, map.height / 2 );
|
||||
map.set_tile(starting_position.x, starting_position.y, TileType::Floor);
|
||||
|
||||
let total_tiles = map.width * map.height;
|
||||
let desired_floor_tiles = (self.floor_percent * total_tiles as f32) as usize;
|
||||
let mut floor_tile_count = map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
||||
let mut digger_count = 0;
|
||||
while floor_tile_count < desired_floor_tiles {
|
||||
let mut drunk_x;
|
||||
let mut drunk_y;
|
||||
match self.spawn_mode {
|
||||
DrunkSpawnMode::StartingPoint => {
|
||||
drunk_x = starting_position.x;
|
||||
drunk_y = starting_position.y;
|
||||
}
|
||||
DrunkSpawnMode::Random => {
|
||||
if digger_count == 0 {
|
||||
drunk_x = starting_position.x;
|
||||
drunk_y = starting_position.y;
|
||||
} else {
|
||||
drunk_x = rng.roll_dice(1, map.width - 3) + 1;
|
||||
drunk_y = rng.roll_dice(1, map.height - 3) + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut drunk_life = self.drunken_lifetime;
|
||||
|
||||
while drunk_life > 0 {
|
||||
map.set_tile(drunk_x, drunk_y, TileType::Wall);
|
||||
map.paint(self.symmetry, self.brush_size, drunk_x, drunk_y);
|
||||
// map.exit_point = Some(Point::new(drunk_x, drunk_y));
|
||||
|
||||
let stagger_direction = rng.roll_dice(1, 4);
|
||||
match stagger_direction {
|
||||
1 => { if drunk_x > 2 { drunk_x -= 1; } }
|
||||
2 => { if drunk_x < map.width-2 { drunk_x += 1; } }
|
||||
3 => { if drunk_y > 2 { drunk_y -=1; } }
|
||||
_ => { if drunk_y < map.height-2 { drunk_y += 1; } }
|
||||
}
|
||||
|
||||
drunk_life -= 1;
|
||||
}
|
||||
|
||||
digger_count += 1;
|
||||
// for t in map.tiles.iter_mut() {
|
||||
// if *t == TileType::DownStairs {
|
||||
// *t = TileType::Floor;
|
||||
// }
|
||||
// }
|
||||
floor_tile_count = map.tiles.iter().filter(|a| **a == TileType::Floor).count();
|
||||
}
|
||||
|
||||
map
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user