Refactor voronoi map builder to use Rust builder pattern
This commit is contained in:
parent
3f692846f8
commit
a6d37bf0dc
@ -1,7 +1,10 @@
|
||||
mod area_starting_points;
|
||||
mod bsp_dungeon;
|
||||
mod bsp_interior;
|
||||
mod cellular_automata;
|
||||
mod common;
|
||||
mod cull_unreachable;
|
||||
mod distant_exit;
|
||||
mod dla;
|
||||
mod drunkard;
|
||||
mod maze;
|
||||
@ -11,14 +14,17 @@ mod room_based_stairs;
|
||||
mod room_based_starting_position;
|
||||
mod simple_map;
|
||||
mod voronoi;
|
||||
mod voronoi_spawning;
|
||||
mod waveform_collapse;
|
||||
|
||||
use crate::{spawner, Map, Position, Rect, SHOW_MAPGEN_VISUALIZER};
|
||||
use ::rltk::RandomNumberGenerator;
|
||||
use area_starting_points::{AreaStartingPosition, XStart, YStart};
|
||||
use bsp_dungeon::BspDungeonBuilder;
|
||||
use bsp_interior::BspInteriorBuilder;
|
||||
use cellular_automata::CellularAutomataBuilder;
|
||||
use common::*;
|
||||
use cull_unreachable::CullUnreachable;
|
||||
use distant_exit::DistantExit;
|
||||
use dla::DLABuilder;
|
||||
use drunkard::DrunkardsWalkBuilder;
|
||||
use maze::MazeBuilder;
|
||||
@ -29,8 +35,11 @@ use room_based_starting_position::RoomBasedStartingPosition;
|
||||
use simple_map::SimpleMapBuilder;
|
||||
use specs::prelude::*;
|
||||
use voronoi::VoronoiCellBuilder;
|
||||
use voronoi_spawning::VoronoiSpawning;
|
||||
use waveform_collapse::WaveformCollapseBuilder;
|
||||
|
||||
use crate::{spawner, Map, Position, Rect, SHOW_MAPGEN_VISUALIZER};
|
||||
|
||||
pub struct BuilderMap {
|
||||
pub spawn_list: Vec<(usize, String)>,
|
||||
pub map: Map,
|
||||
@ -40,6 +49,16 @@ pub struct BuilderMap {
|
||||
}
|
||||
|
||||
impl BuilderMap {
|
||||
fn new(new_depth: i32) -> BuilderMap {
|
||||
BuilderMap {
|
||||
spawn_list: Vec::new(),
|
||||
map: Map::new(new_depth),
|
||||
starting_position: None,
|
||||
rooms: None,
|
||||
history: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn take_snapshot(&mut self) {
|
||||
if SHOW_MAPGEN_VISUALIZER {
|
||||
let mut snapshot = self.map.clone();
|
||||
@ -62,13 +81,7 @@ impl BuilderChain {
|
||||
BuilderChain {
|
||||
starter: None,
|
||||
builders: Vec::new(),
|
||||
build_data: BuilderMap {
|
||||
spawn_list: Vec::new(),
|
||||
map: Map::new(new_depth),
|
||||
starting_position: None,
|
||||
rooms: None,
|
||||
history: Vec::new(),
|
||||
},
|
||||
build_data: BuilderMap::new(new_depth),
|
||||
}
|
||||
}
|
||||
|
||||
@ -155,10 +168,11 @@ pub trait MapBuilder {
|
||||
pub fn random_builder(new_depth: i32, rng: &mut RandomNumberGenerator) -> BuilderChain {
|
||||
let mut builder = BuilderChain::new(new_depth);
|
||||
builder
|
||||
.start_with(SimpleMapBuilder::new())
|
||||
.with(RoomBasedSpawner::new())
|
||||
.with(RoomBasedStartingPosition::new())
|
||||
.with(RoomBasedStairs::new());
|
||||
.start_with(CellularAutomataBuilder::new())
|
||||
.with(AreaStartingPosition::new(XStart::Center, YStart::Center))
|
||||
.with(CullUnreachable::new())
|
||||
.with(VoronoiSpawning::new())
|
||||
.with(DistantExit::new());
|
||||
|
||||
builder
|
||||
}
|
||||
|
79
src/map_builders/area_starting_points.rs
Normal file
79
src/map_builders/area_starting_points.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||
use crate::{Position, TileType};
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum XStart {
|
||||
Left,
|
||||
Center,
|
||||
Right,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub enum YStart {
|
||||
Top,
|
||||
Center,
|
||||
Bottom,
|
||||
}
|
||||
|
||||
pub struct AreaStartingPosition {
|
||||
x: XStart,
|
||||
y: YStart,
|
||||
}
|
||||
|
||||
impl MetaMapBuilder for AreaStartingPosition {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl AreaStartingPosition {
|
||||
#[allow(dead_code)]
|
||||
pub fn new(x: XStart, y: YStart) -> Box<AreaStartingPosition> {
|
||||
Box::new(AreaStartingPosition { x, y })
|
||||
}
|
||||
|
||||
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let seed_x = match self.x {
|
||||
XStart::Left => 1,
|
||||
XStart::Center => build_data.map.width / 2,
|
||||
XStart::Right => build_data.map.width - 2,
|
||||
};
|
||||
|
||||
let seed_y = match self.y {
|
||||
YStart::Top => 1,
|
||||
YStart::Center => build_data.map.height / 2,
|
||||
YStart::Bottom => build_data.map.height - 2,
|
||||
};
|
||||
|
||||
let mut available_floors: Vec<(usize, f32)> = Vec::new();
|
||||
for (idx, tiletype) in build_data.map.tiles.iter().enumerate() {
|
||||
if *tiletype == TileType::Floor {
|
||||
available_floors.push((
|
||||
idx,
|
||||
rltk::DistanceAlg::PythagorasSquared.distance2d(
|
||||
rltk::Point::new(
|
||||
idx as i32 % build_data.map.width,
|
||||
idx as i32 / build_data.map.width,
|
||||
),
|
||||
rltk::Point::new(seed_x, seed_y),
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
if available_floors.is_empty() {
|
||||
panic!("No valid floors to start on");
|
||||
}
|
||||
|
||||
available_floors.sort_by(|a, b| a.1.partial_cmp(&b.1).unwrap());
|
||||
|
||||
let start_x = available_floors[0].0 as i32 % build_data.map.width;
|
||||
let start_y = available_floors[0].0 as i32 / build_data.map.width;
|
||||
|
||||
build_data.starting_position = Some(Position {
|
||||
x: start_x,
|
||||
y: start_y,
|
||||
});
|
||||
}
|
||||
}
|
@ -2,8 +2,8 @@ use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::components::Position;
|
||||
use crate::map_builders::common::{apply_room_to_map, draw_corridor};
|
||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||
|
||||
pub struct BspDungeonBuilder {
|
||||
rects: Vec<Rect>,
|
||||
@ -18,9 +18,7 @@ impl InitialMapBuilder for BspDungeonBuilder {
|
||||
|
||||
impl BspDungeonBuilder {
|
||||
pub fn new() -> Box<BspDungeonBuilder> {
|
||||
Box::new(BspDungeonBuilder {
|
||||
rects: Vec::new(),
|
||||
})
|
||||
Box::new(BspDungeonBuilder { rects: Vec::new() })
|
||||
}
|
||||
|
||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
@ -28,8 +26,12 @@ impl BspDungeonBuilder {
|
||||
self.rects.clear();
|
||||
|
||||
// Start with a single map-sized rectangle
|
||||
self.rects
|
||||
.push(Rect::new(2, 2, build_data.map.width - 5, build_data.map.height - 5));
|
||||
self.rects.push(Rect::new(
|
||||
2,
|
||||
2,
|
||||
build_data.map.width - 5,
|
||||
build_data.map.height - 5,
|
||||
));
|
||||
let first_room = self.rects[0];
|
||||
self.add_subrects(first_room); // Divide the first room
|
||||
|
||||
|
@ -2,9 +2,9 @@ use rltk::RandomNumberGenerator;
|
||||
|
||||
use super::MapBuilder;
|
||||
use crate::components::Position;
|
||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||
use crate::map_builders::common::draw_corridor;
|
||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||
use crate::{spawner, Map, Rect, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||
|
||||
const MIN_ROOM_SIZE: i32 = 8;
|
||||
|
||||
@ -21,9 +21,7 @@ impl InitialMapBuilder for BspInteriorBuilder {
|
||||
|
||||
impl BspInteriorBuilder {
|
||||
pub fn new() -> Box<BspInteriorBuilder> {
|
||||
Box::new(BspInteriorBuilder {
|
||||
rects: Vec::new(),
|
||||
})
|
||||
Box::new(BspInteriorBuilder { rects: Vec::new() })
|
||||
}
|
||||
|
||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
@ -31,8 +29,12 @@ impl BspInteriorBuilder {
|
||||
self.rects.clear();
|
||||
|
||||
// Start with a single map-sized rectangle
|
||||
self.rects
|
||||
.push(Rect::new(1, 1, build_data.map.width - 2, build_data.map.height - 2));
|
||||
self.rects.push(Rect::new(
|
||||
1,
|
||||
1,
|
||||
build_data.map.width - 2,
|
||||
build_data.map.height - 2,
|
||||
));
|
||||
|
||||
let first_room = self.rects[0];
|
||||
self.add_subrects(first_room, rng); // Divide the first room
|
||||
@ -45,7 +47,9 @@ impl BspInteriorBuilder {
|
||||
for y in room.y1..room.y2 {
|
||||
for x in room.x1..room.x2 {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
if idx > 0 && idx < ((build_data.map.width * build_data.map.height) - 1) as usize {
|
||||
if idx > 0
|
||||
&& idx < ((build_data.map.width * build_data.map.height) - 1) as usize
|
||||
{
|
||||
build_data.map.tiles[idx] = TileType::Floor;
|
||||
}
|
||||
}
|
||||
|
@ -2,117 +2,83 @@ use std::collections::HashMap;
|
||||
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use super::common::{
|
||||
use crate::components::Position;
|
||||
use crate::map_builders::common::{
|
||||
generate_voronoi_spawn_regions, remove_unreachable_areas_returning_most_distant,
|
||||
};
|
||||
use super::MapBuilder;
|
||||
use crate::components::Position;
|
||||
use crate::map_builders::{BuilderMap, InitialMapBuilder};
|
||||
use crate::{spawner, Map, TileType, SHOW_MAPGEN_VISUALIZER};
|
||||
|
||||
pub struct CellularAutomataBuilder {
|
||||
map: Map,
|
||||
starting_position: Position,
|
||||
depth: i32,
|
||||
history: Vec<Map>,
|
||||
noise_areas: HashMap<i32, Vec<usize>>,
|
||||
spawn_list: Vec<(usize, String)>,
|
||||
}
|
||||
pub struct CellularAutomataBuilder {}
|
||||
|
||||
impl MapBuilder for CellularAutomataBuilder {
|
||||
fn get_map(&self) -> Map {
|
||||
self.map.clone()
|
||||
}
|
||||
|
||||
fn get_starting_position(&self) -> Position {
|
||||
self.starting_position
|
||||
}
|
||||
|
||||
fn get_snapshot_history(&self) -> Vec<Map> {
|
||||
self.history.clone()
|
||||
}
|
||||
|
||||
fn build_map(&mut self) {
|
||||
self.build();
|
||||
}
|
||||
|
||||
fn take_snapshot(&mut self) {
|
||||
if SHOW_MAPGEN_VISUALIZER {
|
||||
let mut snapshot = self.map.clone();
|
||||
for v in snapshot.revealed_tiles.iter_mut() {
|
||||
*v = true;
|
||||
}
|
||||
|
||||
self.history.push(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
fn get_spawn_list(&self) -> &Vec<(usize, String)> {
|
||||
&self.spawn_list
|
||||
impl InitialMapBuilder for CellularAutomataBuilder {
|
||||
#[allow(dead_code)]
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl CellularAutomataBuilder {
|
||||
pub fn new(new_depth: i32) -> CellularAutomataBuilder {
|
||||
CellularAutomataBuilder {
|
||||
map: Map::new(new_depth),
|
||||
starting_position: Position::default(),
|
||||
depth: new_depth,
|
||||
history: Vec::new(),
|
||||
noise_areas: HashMap::new(),
|
||||
spawn_list: Vec::new(),
|
||||
}
|
||||
pub fn new() -> Box<CellularAutomataBuilder> {
|
||||
Box::new(CellularAutomataBuilder {})
|
||||
}
|
||||
|
||||
fn build(&mut self) {
|
||||
let mut rng = RandomNumberGenerator::new();
|
||||
|
||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
// First we completely randomize the map, setting 55% of it to be floor.
|
||||
for y in 1..self.map.height - 1 {
|
||||
for x in 1..self.map.width - 1 {
|
||||
for y in 1..build_data.map.height - 1 {
|
||||
for x in 1..build_data.map.width - 1 {
|
||||
let roll = rng.roll_dice(1, 100);
|
||||
let idx = self.map.xy_idx(x, y);
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
|
||||
if roll > 55 {
|
||||
self.map.tiles[idx] = TileType::Floor
|
||||
build_data.map.tiles[idx] = TileType::Floor
|
||||
} else {
|
||||
self.map.tiles[idx] = TileType::Wall
|
||||
build_data.map.tiles[idx] = TileType::Wall
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.take_snapshot();
|
||||
build_data.take_snapshot();
|
||||
|
||||
// Now we iteratively apply cellular automata rules
|
||||
for _i in 0..15 {
|
||||
let mut newtiles = self.map.tiles.clone();
|
||||
let mut newtiles = build_data.map.tiles.clone();
|
||||
|
||||
for y in 1..self.map.height - 1 {
|
||||
for x in 1..self.map.width - 1 {
|
||||
let idx = self.map.xy_idx(x, y);
|
||||
for y in 1..build_data.map.height - 1 {
|
||||
for x in 1..build_data.map.width - 1 {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
let mut neighbors = 0;
|
||||
|
||||
if self.map.tiles[idx - 1] == TileType::Wall {
|
||||
if build_data.map.tiles[idx - 1] == TileType::Wall {
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx + 1] == TileType::Wall {
|
||||
if build_data.map.tiles[idx + 1] == TileType::Wall {
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx - self.map.width as usize] == TileType::Wall {
|
||||
if build_data.map.tiles[idx - build_data.map.width as usize] == TileType::Wall {
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx + self.map.width as usize] == TileType::Wall {
|
||||
if build_data.map.tiles[idx + build_data.map.width as usize] == TileType::Wall {
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx - (self.map.width as usize - 1)] == TileType::Wall {
|
||||
if build_data.map.tiles[idx - (build_data.map.width as usize - 1)]
|
||||
== TileType::Wall
|
||||
{
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx - (self.map.width as usize + 1)] == TileType::Wall {
|
||||
if build_data.map.tiles[idx - (build_data.map.width as usize + 1)]
|
||||
== TileType::Wall
|
||||
{
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx + (self.map.width as usize - 1)] == TileType::Wall {
|
||||
if build_data.map.tiles[idx + (build_data.map.width as usize - 1)]
|
||||
== TileType::Wall
|
||||
{
|
||||
neighbors += 1;
|
||||
}
|
||||
if self.map.tiles[idx + (self.map.width as usize + 1)] == TileType::Wall {
|
||||
if build_data.map.tiles[idx + (build_data.map.width as usize + 1)]
|
||||
== TileType::Wall
|
||||
{
|
||||
neighbors += 1;
|
||||
}
|
||||
|
||||
@ -124,45 +90,8 @@ impl CellularAutomataBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
self.map.tiles = newtiles.clone();
|
||||
self.take_snapshot();
|
||||
}
|
||||
|
||||
// Find a starting point; start at the middle and walk left until we find an open tile
|
||||
self.starting_position = Position {
|
||||
x: self.map.width / 2,
|
||||
y: self.map.height / 2,
|
||||
};
|
||||
let mut start_idx = self
|
||||
.map
|
||||
.xy_idx(self.starting_position.x, self.starting_position.y);
|
||||
while self.map.tiles[start_idx] != TileType::Floor {
|
||||
self.starting_position.x -= 1;
|
||||
start_idx = self
|
||||
.map
|
||||
.xy_idx(self.starting_position.x, self.starting_position.y)
|
||||
}
|
||||
|
||||
// Find all tiles we can reach from the starting point
|
||||
let exit_tile = remove_unreachable_areas_returning_most_distant(&mut self.map, start_idx);
|
||||
self.take_snapshot();
|
||||
|
||||
// Place the stairs
|
||||
self.map.tiles[exit_tile] = TileType::DownStairs;
|
||||
self.take_snapshot();
|
||||
|
||||
// Now we build a noise map for use in spawning entities later
|
||||
self.noise_areas = generate_voronoi_spawn_regions(&self.map, &mut rng);
|
||||
|
||||
// Spawn the entities
|
||||
for area in self.noise_areas.iter() {
|
||||
spawner::spawn_region(
|
||||
&self.map,
|
||||
&mut rng,
|
||||
area.1,
|
||||
self.depth,
|
||||
&mut self.spawn_list,
|
||||
);
|
||||
build_data.map.tiles = newtiles.clone();
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
src/map_builders/cull_unreachable.rs
Normal file
46
src/map_builders/cull_unreachable.rs
Normal file
@ -0,0 +1,46 @@
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||
use crate::TileType;
|
||||
|
||||
pub struct CullUnreachable {}
|
||||
|
||||
impl MetaMapBuilder for CullUnreachable {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl CullUnreachable {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Box<CullUnreachable> {
|
||||
Box::new(CullUnreachable {})
|
||||
}
|
||||
|
||||
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||
|
||||
build_data.map.populate_blocked();
|
||||
|
||||
let map_starts: Vec<usize> = vec![start_idx];
|
||||
let dijkstra_map = rltk::DijkstraMap::new(
|
||||
build_data.map.width as usize,
|
||||
build_data.map.height as usize,
|
||||
&map_starts,
|
||||
&build_data.map,
|
||||
1000.0,
|
||||
);
|
||||
|
||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||
if *tile == TileType::Floor {
|
||||
let distance_to_start = dijkstra_map.map[i];
|
||||
|
||||
// We can't go to this tile - so we'll make it a wall
|
||||
if distance_to_start == f32::MAX {
|
||||
*tile = TileType::Wall;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
55
src/map_builders/distant_exit.rs
Normal file
55
src/map_builders/distant_exit.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||
use crate::TileType;
|
||||
|
||||
pub struct DistantExit {}
|
||||
|
||||
impl MetaMapBuilder for DistantExit {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl DistantExit {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Box<DistantExit> {
|
||||
Box::new(DistantExit {})
|
||||
}
|
||||
|
||||
fn build(&mut self, _rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let starting_pos = build_data.starting_position.as_ref().unwrap().clone();
|
||||
let start_idx = build_data.map.xy_idx(starting_pos.x, starting_pos.y);
|
||||
|
||||
build_data.map.populate_blocked();
|
||||
|
||||
let map_starts: Vec<usize> = vec![start_idx];
|
||||
let dijkstra_map = rltk::DijkstraMap::new(
|
||||
build_data.map.width as usize,
|
||||
build_data.map.height as usize,
|
||||
&map_starts,
|
||||
&build_data.map,
|
||||
1000.0,
|
||||
);
|
||||
let mut exit_tile = (0, 0.0f32);
|
||||
for (i, tile) in build_data.map.tiles.iter_mut().enumerate() {
|
||||
if *tile == TileType::Floor {
|
||||
let distance_to_start = dijkstra_map.map[i];
|
||||
|
||||
// We can't get to this tile - so we'll make it a wall
|
||||
if distance_to_start != f32::MAX {
|
||||
// If it is further away than our current exit candidate, move the exit
|
||||
if distance_to_start > exit_tile.1 {
|
||||
exit_tile.0 = i;
|
||||
exit_tile.1 = distance_to_start;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Place a staircase
|
||||
let stairs_idx = exit_tile.0;
|
||||
build_data.map.tiles[stairs_idx] = TileType::DownStairs;
|
||||
build_data.take_snapshot();
|
||||
}
|
||||
}
|
56
src/map_builders/voronoi_spawning.rs
Normal file
56
src/map_builders/voronoi_spawning.rs
Normal file
@ -0,0 +1,56 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rltk::RandomNumberGenerator;
|
||||
|
||||
use crate::map_builders::{BuilderMap, MetaMapBuilder};
|
||||
use crate::{spawner, TileType};
|
||||
|
||||
pub struct VoronoiSpawning {}
|
||||
|
||||
impl MetaMapBuilder for VoronoiSpawning {
|
||||
fn build_map(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
self.build(rng, build_data);
|
||||
}
|
||||
}
|
||||
|
||||
impl VoronoiSpawning {
|
||||
#[allow(dead_code)]
|
||||
pub fn new() -> Box<VoronoiSpawning> {
|
||||
Box::new(VoronoiSpawning {})
|
||||
}
|
||||
|
||||
fn build(&mut self, rng: &mut RandomNumberGenerator, build_data: &mut BuilderMap) {
|
||||
let mut noise_areas: HashMap<i32, Vec<usize>> = HashMap::new();
|
||||
let mut noise = rltk::FastNoise::seeded(rng.roll_dice(1, 65536) as u64);
|
||||
noise.set_noise_type(rltk::NoiseType::Cellular);
|
||||
noise.set_frequency(0.08);
|
||||
noise.set_cellular_distance_function(rltk::CellularDistanceFunction::Manhattan);
|
||||
|
||||
for y in 1..build_data.map.height - 1 {
|
||||
for x in 1..build_data.map.width - 1 {
|
||||
let idx = build_data.map.xy_idx(x, y);
|
||||
if build_data.map.tiles[idx] == TileType::Floor {
|
||||
let cell_value_f = noise.get_noise(x as f32, y as f32) * 10240.0;
|
||||
let cell_value = cell_value_f as i32;
|
||||
|
||||
if noise_areas.contains_key(&cell_value) {
|
||||
noise_areas.get_mut(&cell_value).unwrap().push(idx);
|
||||
} else {
|
||||
noise_areas.insert(cell_value, vec![idx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Spawn the entities
|
||||
for area in noise_areas.iter() {
|
||||
spawner::spawn_region(
|
||||
&build_data.map,
|
||||
rng,
|
||||
area.1,
|
||||
build_data.map.depth,
|
||||
&mut build_data.spawn_list,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user