New modular biomes system and updated world generator
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
use bevy::math::UVec2;
|
||||
use rayon::iter::{IntoParallelIterator, IntoParallelRefIterator, ParallelIterator};
|
||||
use bevy::math::{UVec2, Vec3};
|
||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||
|
||||
use super::chunk::Chunk;
|
||||
|
||||
@@ -7,16 +7,36 @@ pub struct BiomeMap {
|
||||
pub height: usize,
|
||||
pub width: usize,
|
||||
pub biome_count: usize,
|
||||
pub tiles: Vec<Vec<f32>>,
|
||||
pub chunks: Vec<BiomeChunk>,
|
||||
}
|
||||
|
||||
#[derive(Default, Clone, Copy)]
|
||||
pub struct BiomeData {
|
||||
pub moisture: f32,
|
||||
pub temperature: f32,
|
||||
pub continentality: f32,
|
||||
}
|
||||
|
||||
impl Into<Vec3> for &BiomeData {
|
||||
fn into(self) -> Vec3 {
|
||||
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Vec3> for BiomeData {
|
||||
fn into(self) -> Vec3 {
|
||||
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
||||
}
|
||||
}
|
||||
|
||||
impl BiomeMap {
|
||||
pub fn new(size: UVec2, biome_count: usize) -> Self {
|
||||
let len = size.x as usize * size.y as usize * Chunk::AREA;
|
||||
return BiomeMap {
|
||||
height: size.y as usize * Chunk::SIZE,
|
||||
width: size.x as usize * Chunk::SIZE,
|
||||
biome_count,
|
||||
tiles: Vec::with_capacity(size.x as usize * size.y as usize * Chunk::AREA),
|
||||
chunks: Vec::with_capacity(len),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -28,35 +48,44 @@ impl BiomeMap {
|
||||
}
|
||||
|
||||
fn blend_once(&mut self) {
|
||||
let t: Vec<_> = (0..self.height)
|
||||
let c: Vec<BiomeChunk> = (0..self.chunks.len())
|
||||
.into_par_iter()
|
||||
.map(|y| {
|
||||
let mut new_tiles = Vec::with_capacity(self.width);
|
||||
for x in 0..self.width {
|
||||
let kernel = self.get_kernel(x as i32, y as i32);
|
||||
let r = kernel
|
||||
.iter()
|
||||
.filter_map(|f| *f)
|
||||
.fold(vec![0.; self.biome_count], |a, b| {
|
||||
return a.iter().zip(b).map(|v| v.0 + v.1).collect();
|
||||
});
|
||||
.map(|i| &self.chunks[i])
|
||||
.map(|chunk| {
|
||||
let tiles: Vec<_> = (0..Chunk::SIZE)
|
||||
.into_par_iter()
|
||||
.map(|y| {
|
||||
let mut new_tiles = Vec::with_capacity(self.width);
|
||||
for x in 0..Chunk::SIZE {
|
||||
let kernel = self.get_kernel(x as i32, y as i32);
|
||||
let r = kernel
|
||||
.iter()
|
||||
.filter_map(|f| *f)
|
||||
.fold(vec![0.; self.biome_count], |a, b| {
|
||||
return a.iter().zip(b).map(|v| v.0 + v.1).collect();
|
||||
});
|
||||
|
||||
let sum: f32 = r.iter().sum();
|
||||
if sum == 0. {
|
||||
new_tiles.push(vec![0.; self.biome_count]);
|
||||
continue;
|
||||
}
|
||||
new_tiles.push(r.iter().map(|f| f / sum).collect());
|
||||
}
|
||||
return new_tiles;
|
||||
let sum: f32 = r.iter().sum();
|
||||
if sum == 0. {
|
||||
new_tiles.push(vec![0.; self.biome_count]);
|
||||
continue;
|
||||
}
|
||||
new_tiles.push(r.iter().map(|f| f / sum).collect());
|
||||
}
|
||||
return new_tiles;
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
return BiomeChunk {
|
||||
tiles,
|
||||
data: chunk.data,
|
||||
};
|
||||
})
|
||||
.flatten()
|
||||
.collect();
|
||||
|
||||
self.tiles = t;
|
||||
self.chunks = c;
|
||||
}
|
||||
|
||||
pub fn get_kernel(&self, x: i32, y: i32) -> [Option<&Vec<f32>>; 9] {
|
||||
fn get_kernel(&self, x: i32, y: i32) -> [Option<&Vec<f32>>; 9] {
|
||||
return [
|
||||
self.get_biome(x - 1, y - 1),
|
||||
self.get_biome(x, y - 1),
|
||||
@@ -78,7 +107,37 @@ impl BiomeMap {
|
||||
return None;
|
||||
}
|
||||
|
||||
return Some(&self.tiles[x as usize + y as usize * self.width]);
|
||||
let cx = x as usize / Chunk::SIZE;
|
||||
let cy = y as usize / Chunk::SIZE;
|
||||
|
||||
let chunk = &self.chunks[cx + cy * Chunk::SIZE];
|
||||
|
||||
return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE));
|
||||
}
|
||||
|
||||
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData {
|
||||
let cx = x / Chunk::SIZE;
|
||||
let cy = y / Chunk::SIZE;
|
||||
|
||||
let chunk = &self.chunks[cx + cy * Chunk::SIZE];
|
||||
|
||||
return chunk.get_biome_data(x - cx * Chunk::SIZE, y - cy * Chunk::SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BiomeChunk {
|
||||
pub tiles: Vec<Vec<f32>>,
|
||||
pub data: [BiomeData; Chunk::AREA],
|
||||
}
|
||||
|
||||
impl BiomeChunk {
|
||||
pub fn get_biome(&self, x: usize, y: usize) -> &Vec<f32> {
|
||||
return &self.tiles[x as usize + y as usize * Chunk::SIZE];
|
||||
}
|
||||
|
||||
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData {
|
||||
return &self.data[x + y * Chunk::SIZE];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,18 +149,27 @@ mod tests {
|
||||
#[test]
|
||||
fn biome_blend() {
|
||||
let mut biome = BiomeMap::new(UVec2::ONE * 16, 8);
|
||||
let w = biome.width / Chunk::SIZE;
|
||||
let h = biome.height / Chunk::SIZE;
|
||||
|
||||
for y in 0..biome.height {
|
||||
for x in 0..biome.width {
|
||||
for y in 0..h {
|
||||
for x in 0..w {
|
||||
let mut b = vec![0.; biome.biome_count];
|
||||
let i = x / Chunk::SIZE;
|
||||
let z = y / Chunk::SIZE;
|
||||
let idx = (i + z) % biome.biome_count;
|
||||
let idx = (x + y) % biome.biome_count;
|
||||
b[idx] = 1.;
|
||||
biome.tiles.push(b);
|
||||
biome.chunks.push(generate_chunk(x, y, b));
|
||||
}
|
||||
}
|
||||
|
||||
biome.blend(8);
|
||||
}
|
||||
|
||||
fn generate_chunk(x: usize, y: usize, biome: Vec<f32>) -> BiomeChunk {
|
||||
let chunk = BiomeChunk {
|
||||
data: [BiomeData::default(); Chunk::AREA],
|
||||
tiles: (0..Chunk::AREA).into_iter().map(|_| biome.clone()).collect(),
|
||||
};
|
||||
|
||||
return chunk;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
use crate::hex_utils::SHORT_DIAGONAL;
|
||||
use bevy::prelude::*;
|
||||
|
||||
use super::biome_map::BiomeData;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Chunk {
|
||||
pub heights: [f32; Chunk::AREA],
|
||||
pub textures: [[u32; 2]; Chunk::AREA],
|
||||
pub moisture: [f32; Chunk::AREA],
|
||||
pub temperature: [f32; Chunk::AREA],
|
||||
pub biome_data: [BiomeData; Chunk::AREA],
|
||||
pub chunk_offset: IVec2,
|
||||
}
|
||||
|
||||
@@ -15,8 +16,7 @@ impl Default for Chunk {
|
||||
Self {
|
||||
heights: [0.; Chunk::AREA],
|
||||
textures: [[0; 2]; Chunk::AREA],
|
||||
moisture: [0.; Chunk::AREA],
|
||||
temperature: [0.; Chunk::AREA],
|
||||
biome_data: [BiomeData::default(); Chunk::AREA],
|
||||
chunk_offset: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,12 +7,13 @@ use super::chunk::Chunk;
|
||||
#[derive(Resource, Reflect, Default)]
|
||||
#[reflect(Resource)]
|
||||
pub struct GenerationConfig {
|
||||
pub noise_scale: f64,
|
||||
pub sea_level: f64,
|
||||
pub border_size: f32,
|
||||
pub biome_blend: usize,
|
||||
pub moisture_layer: NoiseConfig,
|
||||
pub temperature_layer: NoiseConfig,
|
||||
pub continent_layer: NoiseConfig,
|
||||
pub size: UVec2,
|
||||
pub layers: Vec<GeneratorLayer>,
|
||||
}
|
||||
|
||||
impl GenerationConfig {
|
||||
@@ -24,7 +25,13 @@ impl GenerationConfig {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Reflect, InspectorOptions, Serialize, Deserialize, Debug, Clone)]
|
||||
#[derive(Serialize, Deserialize, Default, Reflect, Clone, Debug)]
|
||||
pub struct NoiseConfig {
|
||||
pub scale: f64,
|
||||
pub layers: Vec<GeneratorLayer>,
|
||||
}
|
||||
|
||||
#[derive(Reflect, InspectorOptions, Serialize, Deserialize, Debug, Clone, Default)]
|
||||
pub struct GeneratorLayer {
|
||||
pub strength: f64,
|
||||
pub min_value: f64,
|
||||
|
||||
@@ -58,12 +58,12 @@ impl Map {
|
||||
|
||||
pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
|
||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||
return chunk.moisture[pos.to_chunk_local_index()];
|
||||
return chunk.biome_data[pos.to_chunk_local_index()].moisture;
|
||||
}
|
||||
|
||||
pub fn get_tempurature(&self, pos: &HexCoord) -> f32 {
|
||||
let chunk = &self.chunks[pos.to_chunk_index(self.width)];
|
||||
return chunk.temperature[pos.to_chunk_local_index()];
|
||||
return chunk.biome_data[pos.to_chunk_local_index()].temperature;
|
||||
}
|
||||
|
||||
pub fn get_center(&self) -> Vec3 {
|
||||
|
||||
Reference in New Issue
Block a user