Added NoiseGenerator
This commit is contained in:
parent
416cd633eb
commit
be1d9e95bb
39
README.md
39
README.md
|
@ -7,28 +7,27 @@
|
||||||
Generate procedural maps for games. [Try it in the browser](https://klangner.github.io/mapgen.rs/) using WebAssembly.
|
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
|
### Implemented filters
|
||||||
* [x] BSP Interior
|
|
||||||
* [x] BSP Rooms
|
* [x] Area exit point
|
||||||
* [x] Cellular automata
|
* [x] Area starting point
|
||||||
* [ ] Diffusion-Limited Aggregation (DLA)
|
* [x] BSP Interior
|
||||||
* [x] Drunkard's walk
|
* [x] BSP Rooms
|
||||||
* [ ] Maze
|
* [x] Cellular automata
|
||||||
* [ ] Prefabs
|
* [x] Cull unreachable areas
|
||||||
* [x] Simple rooms
|
* [ ] Diffusion-Limited Aggregation (DLA)
|
||||||
* [ ] Voronoi hive
|
* [x] Drunkard's walk
|
||||||
* [ ] Wave Function Collapse
|
* [ ] Maze
|
||||||
* Map modifiers (filters)
|
* [x] Noise generator
|
||||||
* [x] Area exit point
|
* [ ] Prefabs
|
||||||
* [x] Area starting point
|
* [x] Room corridors nearest
|
||||||
* [x] Cellular automata
|
* [x] Simple rooms
|
||||||
* [x] Cull unreachable areas
|
* [ ] Voronoi hive
|
||||||
* [x] Room corridors nearest
|
* [ ] Wave Function Collapse
|
||||||
* [ ] Voronoi spawning
|
|
||||||
|
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
|
@ -5,7 +5,13 @@
|
||||||
```
|
```
|
||||||
wasm-pack build
|
wasm-pack build
|
||||||
cd www
|
cd www
|
||||||
npm run start
|
npm run server
|
||||||
|
```
|
||||||
|
|
||||||
|
Deply application
|
||||||
|
```
|
||||||
|
cd www
|
||||||
|
npm run deploy
|
||||||
```
|
```
|
||||||
|
|
||||||
This app uses:
|
This app uses:
|
||||||
|
|
|
@ -2,16 +2,7 @@ use wasm_bindgen::prelude::*;
|
||||||
use web_sys;
|
use web_sys;
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use mapgen::{MapBuilder, TileType};
|
use mapgen::{MapBuilder, TileType};
|
||||||
use mapgen::filter::{
|
use mapgen::filter::*;
|
||||||
CellularAutomata,
|
|
||||||
SimpleRooms,
|
|
||||||
BspInterior,
|
|
||||||
{AreaStartingPosition, XStart, YStart},
|
|
||||||
CullUnreachable,
|
|
||||||
DistantExit,
|
|
||||||
NearestCorridors,
|
|
||||||
DrunkardsWalk,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
|
@ -36,6 +27,7 @@ impl World {
|
||||||
World::print_map_info(format!("Cellular Automata with the seed: {}", seed));
|
World::print_map_info(format!("Cellular Automata with the seed: {}", seed));
|
||||||
let mut rng = StdRng::seed_from_u64(seed as u64);
|
let mut rng = StdRng::seed_from_u64(seed as u64);
|
||||||
let map = MapBuilder::new()
|
let map = MapBuilder::new()
|
||||||
|
.with(NoiseGenerator::uniform())
|
||||||
.with(CellularAutomata::new())
|
.with(CellularAutomata::new())
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
.with(CullUnreachable::new())
|
.with(CullUnreachable::new())
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack --config webpack.config.js",
|
"build": "webpack --config webpack.config.js",
|
||||||
"start": "webpack-dev-server",
|
"server": "webpack-dev-server",
|
||||||
"deploy": "gh-pages -d dist"
|
"deploy": "gh-pages -d dist"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
|
@ -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)
|
//! 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.
|
//! for more information about the algorithm behind this generator.
|
||||||
//!
|
//!
|
||||||
//! Since this algorithm works in interations it is possible to take existing map
|
//! This algorithm requires that map first is filtered with some noise.
|
||||||
//! and apply single interaction to it. This is the idea behind MapModifier implementation.
|
//! For example `UniformNoise`. It can also be apply to any other non empty map.
|
||||||
//!
|
//!
|
||||||
//! Example generator usage:
|
//! Example usage:
|
||||||
//! ```
|
//! ```
|
||||||
//! use rand::prelude::*;
|
//! use rand::prelude::*;
|
||||||
//! use mapgen::{Map, MapFilter};
|
//! use mapgen::{Map, MapFilter};
|
||||||
|
@ -26,35 +26,27 @@ use crate::MapFilter;
|
||||||
use crate::{Map, TileType};
|
use crate::{Map, TileType};
|
||||||
|
|
||||||
|
|
||||||
/// Map generator and modifier
|
/// Map filter
|
||||||
pub struct CellularAutomata {}
|
pub struct CellularAutomata {
|
||||||
|
num_iteraction: u32,
|
||||||
|
}
|
||||||
|
|
||||||
impl MapFilter for CellularAutomata {
|
impl MapFilter for CellularAutomata {
|
||||||
fn modify_map(&self, rng: &mut StdRng, map: &Map) -> Map {
|
fn modify_map(&self, _rng: &mut StdRng, map: &Map) -> Map {
|
||||||
self.build(map, rng)
|
self.build(map)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CellularAutomata {
|
impl CellularAutomata {
|
||||||
/// Create generator which will create map with the given dimension.
|
/// Create generator which will create map with the given dimension.
|
||||||
pub fn new() -> Box<CellularAutomata> {
|
pub fn new() -> Box<CellularAutomata> {
|
||||||
Box::new(CellularAutomata {})
|
Box::new(CellularAutomata { num_iteraction: 15})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate map
|
/// Generate map
|
||||||
fn build(&self, map: &Map, rng: &mut StdRng) -> Map {
|
fn build(&self, map: &Map) -> Map {
|
||||||
let mut new_map = map.clone();
|
let mut new_map = map.clone();
|
||||||
// First we completely randomize the map, setting 55% of it to be floor.
|
for _ in 0..self.num_iteraction {
|
||||||
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 {
|
|
||||||
new_map = apply_iteration(&new_map);
|
new_map = apply_iteration(&new_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,14 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
|
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
|
||||||
//! use mapgen::filter::{
|
//! use mapgen::filter::{
|
||||||
|
//! NoiseGenerator,
|
||||||
//! CellularAutomata,
|
//! CellularAutomata,
|
||||||
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
||||||
//! };
|
//! };
|
||||||
//! use mapgen::geometry::Point;
|
//! use mapgen::geometry::Point;
|
||||||
//!
|
//!
|
||||||
//! let map = MapBuilder::new()
|
//! let map = MapBuilder::new()
|
||||||
|
//! .with(NoiseGenerator::uniform())
|
||||||
//! .with(CellularAutomata::new())
|
//! .with(CellularAutomata::new())
|
||||||
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
//! .build_map(80, 50);
|
//! .build_map(80, 50);
|
||||||
|
@ -32,6 +34,7 @@ pub mod cellular_automata;
|
||||||
pub mod cull_unreachable;
|
pub mod cull_unreachable;
|
||||||
pub mod distant_exit;
|
pub mod distant_exit;
|
||||||
pub mod drunkard;
|
pub mod drunkard;
|
||||||
|
pub mod noise_generator;
|
||||||
pub mod simple_rooms;
|
pub mod simple_rooms;
|
||||||
pub mod rooms_corridors_nearest;
|
pub mod rooms_corridors_nearest;
|
||||||
pub mod starting_point;
|
pub mod starting_point;
|
||||||
|
@ -42,6 +45,7 @@ pub use cellular_automata::CellularAutomata;
|
||||||
pub use cull_unreachable::CullUnreachable;
|
pub use cull_unreachable::CullUnreachable;
|
||||||
pub use distant_exit::DistantExit;
|
pub use distant_exit::DistantExit;
|
||||||
pub use drunkard::DrunkardsWalk;
|
pub use drunkard::DrunkardsWalk;
|
||||||
|
pub use noise_generator::NoiseGenerator;
|
||||||
pub use simple_rooms::SimpleRooms;
|
pub use simple_rooms::SimpleRooms;
|
||||||
pub use rooms_corridors_nearest::NearestCorridors;
|
pub use rooms_corridors_nearest::NearestCorridors;
|
||||||
pub use starting_point::{AreaStartingPosition, XStart, YStart};
|
pub use starting_point::{AreaStartingPosition, XStart, YStart};
|
||||||
|
|
65
src/filter/noise_generator.rs
Normal file
65
src/filter/noise_generator.rs
Normal file
|
@ -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<NoiseGenerator> {
|
||||||
|
Box::new(NoiseGenerator {
|
||||||
|
prob,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create uniform noise (Probablity 0.5)
|
||||||
|
pub fn uniform() -> Box<NoiseGenerator> {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
11
src/lib.rs
11
src/lib.rs
|
@ -10,12 +10,14 @@
|
||||||
//! ```
|
//! ```
|
||||||
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
|
//! use mapgen::{MapFilter, MapBuilder, Map, TileType};
|
||||||
//! use mapgen::filter::{
|
//! use mapgen::filter::{
|
||||||
|
//! NoiseGenerator,
|
||||||
//! CellularAutomata,
|
//! CellularAutomata,
|
||||||
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
//! starting_point::{AreaStartingPosition, XStart, YStart}
|
||||||
//! };
|
//! };
|
||||||
//! use mapgen::geometry::Point;
|
//! use mapgen::geometry::Point;
|
||||||
//!
|
//!
|
||||||
//! let map = MapBuilder::new()
|
//! let map = MapBuilder::new()
|
||||||
|
//! .with(NoiseGenerator::uniform())
|
||||||
//! .with(CellularAutomata::new())
|
//! .with(CellularAutomata::new())
|
||||||
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
//! .with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
//! .build_map(80, 50);
|
//! .build_map(80, 50);
|
||||||
|
@ -31,6 +33,7 @@ pub mod geometry;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
|
|
||||||
pub use map::{Map, Symmetry, TileType};
|
pub use map::{Map, Symmetry, TileType};
|
||||||
|
pub use filter::*;
|
||||||
|
|
||||||
pub (crate) mod dijkstra;
|
pub (crate) mod dijkstra;
|
||||||
pub (crate) mod random;
|
pub (crate) mod random;
|
||||||
|
@ -90,12 +93,16 @@ impl MapBuilder {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use filter::CellularAutomata;
|
use filter::{
|
||||||
use filter::{AreaStartingPosition, XStart, YStart};
|
CellularAutomata,
|
||||||
|
NoiseGenerator,
|
||||||
|
{AreaStartingPosition, XStart, YStart},
|
||||||
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_ca_map() {
|
fn test_ca_map() {
|
||||||
let map = MapBuilder::new()
|
let map = MapBuilder::new()
|
||||||
|
.with(NoiseGenerator::new(0.55))
|
||||||
.with(CellularAutomata::new())
|
.with(CellularAutomata::new())
|
||||||
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
.with(AreaStartingPosition::new(XStart::CENTER, YStart::CENTER))
|
||||||
.build_map(80, 50);
|
.build_map(80, 50);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user