Added NoiseGenerator
This commit is contained in:
parent
416cd633eb
commit
be1d9e95bb
19
README.md
19
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
|
||||
### 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
|
||||
* Map modifiers (filters)
|
||||
* [x] Area exit point
|
||||
* [x] Area starting point
|
||||
* [x] Cellular automata
|
||||
* [x] Cull unreachable areas
|
||||
* [x] Room corridors nearest
|
||||
* [ ] Voronoi spawning
|
||||
|
||||
|
||||
## Usage
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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<CellularAutomata> {
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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};
|
||||
|
|
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::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);
|
||||
|
|
Loading…
Reference in New Issue
Block a user