From be1d9e95bb4aaa0b68dcf1bce0d4c5229833349d Mon Sep 17 00:00:00 2001 From: klangner Date: Wed, 23 Sep 2020 10:31:13 +0200 Subject: [PATCH] Added NoiseGenerator --- README.md | 39 ++++++++++---------- demo/README.md | 8 +++- demo/src/lib.rs | 12 +----- demo/www/package.json | 2 +- src/filter/cellular_automata.rs | 34 +++++++---------- src/filter/mod.rs | 4 ++ src/filter/noise_generator.rs | 65 +++++++++++++++++++++++++++++++++ src/lib.rs | 11 +++++- 8 files changed, 120 insertions(+), 55 deletions(-) create mode 100644 src/filter/noise_generator.rs diff --git a/README.md b/README.md index 680e03d..962aabf 100644 --- a/README.md +++ b/README.md @@ -7,28 +7,27 @@ Generate procedural maps for games. [Try it in the browser](https://klangner.github.io/mapgen.rs/) using WebAssembly. -## Features +## Map filters -### Dungeons +This library consists of different map filters which can be combined to create custom map generator. - * Map generators - * [x] BSP Interior - * [x] BSP Rooms - * [x] Cellular automata - * [ ] Diffusion-Limited Aggregation (DLA) - * [x] Drunkard's walk - * [ ] Maze - * [ ] Prefabs - * [x] Simple rooms - * [ ] Voronoi hive - * [ ] Wave Function Collapse - * Map modifiers (filters) - * [x] Area exit point - * [x] Area starting point - * [x] Cellular automata - * [x] Cull unreachable areas - * [x] Room corridors nearest - * [ ] Voronoi spawning +### Implemented filters + + * [x] Area exit point + * [x] Area starting point + * [x] BSP Interior + * [x] BSP Rooms + * [x] Cellular automata + * [x] Cull unreachable areas + * [ ] Diffusion-Limited Aggregation (DLA) + * [x] Drunkard's walk + * [ ] Maze + * [x] Noise generator + * [ ] Prefabs + * [x] Room corridors nearest + * [x] Simple rooms + * [ ] Voronoi hive + * [ ] Wave Function Collapse ## Usage diff --git a/demo/README.md b/demo/README.md index 5d70049..4f879dd 100644 --- a/demo/README.md +++ b/demo/README.md @@ -5,7 +5,13 @@ ``` wasm-pack build cd www -npm run start +npm run server +``` + +Deply application +``` +cd www +npm run deploy ``` This app uses: diff --git a/demo/src/lib.rs b/demo/src/lib.rs index 193457c..9988ca0 100644 --- a/demo/src/lib.rs +++ b/demo/src/lib.rs @@ -2,16 +2,7 @@ use wasm_bindgen::prelude::*; use web_sys; use rand::prelude::*; use mapgen::{MapBuilder, TileType}; -use mapgen::filter::{ - CellularAutomata, - SimpleRooms, - BspInterior, - {AreaStartingPosition, XStart, YStart}, - CullUnreachable, - DistantExit, - NearestCorridors, - DrunkardsWalk, -}; +use mapgen::filter::*; #[wasm_bindgen] @@ -36,6 +27,7 @@ impl World { World::print_map_info(format!("Cellular Automata with the seed: {}", seed)); let mut rng = StdRng::seed_from_u64(seed as u64); let map = MapBuilder::new() + .with(NoiseGenerator::uniform()) .with(CellularAutomata::new()) .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) .with(CullUnreachable::new()) diff --git a/demo/www/package.json b/demo/www/package.json index 85b7c26..0563a26 100644 --- a/demo/www/package.json +++ b/demo/www/package.json @@ -8,7 +8,7 @@ }, "scripts": { "build": "webpack --config webpack.config.js", - "start": "webpack-dev-server", + "server": "webpack-dev-server", "deploy": "gh-pages -d dist" }, "repository": { diff --git a/src/filter/cellular_automata.rs b/src/filter/cellular_automata.rs index 2a8332a..24728ed 100644 --- a/src/filter/cellular_automata.rs +++ b/src/filter/cellular_automata.rs @@ -1,12 +1,12 @@ -//! Cellular automata map generator and modifier. +//! Cellular automata map filter. //! //! Check this [article](http://www.roguebasin.com/index.php?title=Cellular_Automata_Method_for_Generating_Random_Cave-Like_Levels) //! for more information about the algorithm behind this generator. //! -//! Since this algorithm works in interations it is possible to take existing map -//! and apply single interaction to it. This is the idea behind MapModifier implementation. +//! This algorithm requires that map first is filtered with some noise. +//! For example `UniformNoise`. It can also be apply to any other non empty map. //! -//! Example generator usage: +//! Example usage: //! ``` //! use rand::prelude::*; //! use mapgen::{Map, MapFilter}; @@ -26,35 +26,27 @@ use crate::MapFilter; use crate::{Map, TileType}; -/// Map generator and modifier -pub struct CellularAutomata {} +/// Map filter +pub struct CellularAutomata { + num_iteraction: u32, +} impl MapFilter for CellularAutomata { - fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { - self.build(map, rng) + fn modify_map(&self, _rng: &mut StdRng, map: &Map) -> Map { + self.build(map) } } impl CellularAutomata { /// Create generator which will create map with the given dimension. pub fn new() -> Box { - Box::new(CellularAutomata {}) + Box::new(CellularAutomata { num_iteraction: 15}) } /// Generate map - fn build(&self, map: &Map, rng: &mut StdRng) -> Map { + fn build(&self, map: &Map) -> Map { let mut new_map = map.clone(); - // First we completely randomize the map, setting 55% of it to be floor. - 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 { 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 { + for _ in 0..self.num_iteraction { new_map = apply_iteration(&new_map); } diff --git a/src/filter/mod.rs b/src/filter/mod.rs index 53e91bd..b91566b 100644 --- a/src/filter/mod.rs +++ b/src/filter/mod.rs @@ -10,12 +10,14 @@ //! ``` //! use mapgen::{MapFilter, MapBuilder, Map, TileType}; //! use mapgen::filter::{ +//! NoiseGenerator, //! CellularAutomata, //! starting_point::{AreaStartingPosition, XStart, YStart} //! }; //! use mapgen::geometry::Point; //! //! let map = MapBuilder::new() +//! .with(NoiseGenerator::uniform()) //! .with(CellularAutomata::new()) //! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) //! .build_map(80, 50); @@ -32,6 +34,7 @@ pub mod cellular_automata; pub mod cull_unreachable; pub mod distant_exit; pub mod drunkard; +pub mod noise_generator; pub mod simple_rooms; pub mod rooms_corridors_nearest; pub mod starting_point; @@ -42,6 +45,7 @@ pub use cellular_automata::CellularAutomata; pub use cull_unreachable::CullUnreachable; pub use distant_exit::DistantExit; pub use drunkard::DrunkardsWalk; +pub use noise_generator::NoiseGenerator; pub use simple_rooms::SimpleRooms; pub use rooms_corridors_nearest::NearestCorridors; pub use starting_point::{AreaStartingPosition, XStart, YStart}; diff --git a/src/filter/noise_generator.rs b/src/filter/noise_generator.rs new file mode 100644 index 0000000..1a12745 --- /dev/null +++ b/src/filter/noise_generator.rs @@ -0,0 +1,65 @@ +//! Apply noise to the map. +//! Each cell will be set to Floor with the given probabilty. +//! +//! Example usage: +//! ``` +//! use rand::prelude::*; +//! use mapgen::{Map, MapFilter}; +//! use mapgen::filter::NoiseGenerator; +//! +//! let mut rng = StdRng::seed_from_u64(100); +//! let gen = NoiseGenerator::uniform(); +//! 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 crate::MapFilter; +use crate::{Map, TileType}; + + +/// Map noise generator +pub struct NoiseGenerator { + prob: f32, +} + +impl MapFilter for NoiseGenerator { + fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map { + self.build(map, rng) + } +} + +impl NoiseGenerator { + /// Create noise with custom probability + pub fn new(prob: f32) -> Box { + Box::new(NoiseGenerator { + prob, + }) + } + + /// Create uniform noise (Probablity 0.5) + pub fn uniform() -> Box { + Box::new(NoiseGenerator { + prob: 0.5, + }) + } + + /// Generate map + fn build(&self, map: &Map, rng: &mut StdRng) -> Map { + let mut new_map = map.clone(); + let p = (self.prob * 100.0) as u32; + for y in 1..new_map.height-1 { + for x in 1..new_map.width-1 { + let roll = rng.next_u32() % 100; + if roll > p { new_map.set_tile(x, y, TileType::Floor) } + else { new_map.set_tile(x, y, TileType::Wall) } + } + } + + new_map + } + +} diff --git a/src/lib.rs b/src/lib.rs index ef4e10e..f5c1b65 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,12 +10,14 @@ //! ``` //! use mapgen::{MapFilter, MapBuilder, Map, TileType}; //! use mapgen::filter::{ +//! NoiseGenerator, //! CellularAutomata, //! starting_point::{AreaStartingPosition, XStart, YStart} //! }; //! use mapgen::geometry::Point; //! //! let map = MapBuilder::new() +//! .with(NoiseGenerator::uniform()) //! .with(CellularAutomata::new()) //! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) //! .build_map(80, 50); @@ -31,6 +33,7 @@ pub mod geometry; pub mod map; pub use map::{Map, Symmetry, TileType}; +pub use filter::*; pub (crate) mod dijkstra; pub (crate) mod random; @@ -90,12 +93,16 @@ impl MapBuilder { #[cfg(test)] mod tests { use super::*; - use filter::CellularAutomata; - use filter::{AreaStartingPosition, XStart, YStart}; + use filter::{ + CellularAutomata, + NoiseGenerator, + {AreaStartingPosition, XStart, YStart}, + }; #[test] fn test_ca_map() { let map = MapBuilder::new() + .with(NoiseGenerator::new(0.55)) .with(CellularAutomata::new()) .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER)) .build_map(80, 50);