chunks generation (not tested)

This commit is contained in:
Arkitu 2025-06-12 21:52:30 +02:00
parent 00f75f2de6
commit eb3742e21d
2 changed files with 115 additions and 63 deletions

View File

@ -7,6 +7,7 @@ use bevy::{
picking::PickSet,
prelude::*,
render::mesh::{Indices, PrimitiveTopology},
utils::HashMap,
};
use noise::{Fbm, MultiFractal, NoiseFn, Perlin};
use rand::{thread_rng, Rng, SeedableRng};
@ -45,8 +46,9 @@ pub const REAL_WIDTH: f32 = 8000.;
pub const CELL_AREA: f32 = REAL_HEIGHT * REAL_WIDTH / CELLS as f32;
pub const CELLS_TARGET_NUMBER: usize = 100_000;
pub const CHUNKS_RESOLUTION: usize = 2;
pub const CELLS_PER_CHUNK: usize = CELLS_TARGET_NUMBER / CHUNKS_RESOLUTION.pow(2);
pub const CELLS: usize = CELLS_PER_CHUNK * CHUNKS_RESOLUTION.pow(2);
pub const CHUNKS: usize = CHUNKS_RESOLUTION.pow(2);
pub const CELLS_PER_CHUNK: usize = CELLS_TARGET_NUMBER / CHUNKS;
pub const CELLS: usize = CELLS_PER_CHUNK * CHUNKS;
#[derive(Resource)]
struct Seed(u32);
@ -58,7 +60,7 @@ pub struct Voronoi(voronoice::Voronoi);
pub struct MapMarker;
#[derive(Component)]
struct MapMeshColors(Vec<[f32; 4]>);
struct MeshColors(Vec<[f32; 4]>);
#[derive(Resource)]
pub struct CellsEntities(Vec<Entity>);
@ -105,10 +107,8 @@ fn setup(
let mut cells = Vec::with_capacity(CELLS);
let z_noise = Fbm::<Perlin>::new(seed.0);
let moisture_noise = Fbm::<Perlin>::new(seed.0 + 1).set_frequency(2.);
let mut res = 0;
for i in 0..CELLS {
let c = voronoi.cell(i);
res += c.iter_neighbors().count();
let site = c.site_position();
let z = get_altitude(&z_noise, &[site.x as f32, site.y as f32]);
let _m = (
@ -131,17 +131,27 @@ fn setup(
vertices: vec![],
});
}
dbg!(res as f64 / CELLS as f64);
let mut poss = Vec::new();
let mut indices = Vec::new();
// let mut poss = [Vec::new(); CHUNKS];
let mut indices: [Vec<u32>; CHUNKS] = std::array::from_fn(|_| Vec::new());
// let mut normals = Vec::new();
for (i, pos) in voronoi.sites().iter().enumerate() {
let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]);
poss.push(Vec3::new(pos.x as f32, pos.y as f32, z));
cells[i].vertices.push(i);
}
let mut poss = voronoi.sites().chunks_exact(CELLS_PER_CHUNK).map(|ch| {
ch.iter()
.map(|pos| {
let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]);
Vec3::new(pos.x as f32, pos.y as f32, z)
})
.collect::<Vec<_>>()
});
let mut poss: [Vec<Vec3>; CHUNKS] = std::array::from_fn(|_| poss.next().unwrap());
// for (i, pos) in voronoi.sites().iter().enumerate() {
// let z = get_altitude(&z_noise, &[pos.x as f32, pos.y as f32]);
// poss.push(Vec3::new(pos.x as f32, pos.y as f32, z));
// cells[i].vertices.push(i);
// }
// let mut hybrid_cells: HashMap<usize, usize> = HashMap::new();
for t in voronoi.triangulation().triangles.chunks_exact(3) {
let on_hull = t
.iter()
@ -151,7 +161,53 @@ fn setup(
if on_hull > 0 {
continue;
}
indices.extend_from_slice(&[t[2] as u32, t[1] as u32, t[0] as u32]);
let mut chs = t.iter().map(|c| Cell::chunk_from_id(*c));
let chs: [usize; 3] = std::array::from_fn(|_| chs.next().unwrap());
// Add vertex to chunk if it is from an external chunk but we need it for a triangle. Else, just make the triangle
if chs[1] == chs[2] && chs[0] != chs[1] {
poss[chs[1]].push(poss[chs[0]][t[0] % CELLS_PER_CHUNK]);
// hybrid_cells.insert(chs[0], chs[1]);
indices[chs[1]].push((poss[chs[1]].len() - 1) as u32);
} else {
indices[chs[0]].push((t[0] % CELLS_PER_CHUNK) as u32);
}
if chs[0] == chs[2] && chs[1] != chs[0] {
poss[chs[0]].push(poss[chs[1]][t[1] % CELLS_PER_CHUNK]);
// hybrid_cells.insert(chs[1], chs[0]);
indices[chs[0]].push((poss[chs[0]].len() - 1) as u32);
} else {
indices[chs[1]].push((t[1] % CELLS_PER_CHUNK) as u32);
}
if chs[0] == chs[1] && chs[2] != chs[0] {
poss[chs[0]].push(poss[chs[2]][t[2] % CELLS_PER_CHUNK]);
// hybrid_cells.insert(chs[2], chs[0]);
indices[chs[0]].push((poss[chs[0]].len() - 1) as u32);
} else {
indices[chs[2]].push((t[2] % CELLS_PER_CHUNK) as u32);
}
}
let mut cells_entities = Vec::with_capacity(cells.len());
for cell in cells {
let kind = cell.kind;
// let id = cell.voronoi_id;
let mut cmd = cmds.spawn(cell);
// if let Some(ch) = hybrid_cells.get(&id) {
// cmd.insert(GhostCell(*ch));
// }
match kind {
CellKind::Grass | CellKind::Forest => {
cmd.insert((
Wealth(0),
Regeneration {
last_update: Duration::ZERO,
full_growth_duration: kind.regen_full_growth_duration(),
},
));
}
_ => {}
}
cmd.observe(self::cells::on_click);
cells_entities.push(cmd.id());
}
// indices.extend(voronoi.triangulation().triangles.iter().map(|t| *t as u32));
@ -176,63 +232,47 @@ fn setup(
// cd.vertices.extend_from_slice(&[i, i + v, i + v + 1]);
// }
// }
for (poss, indices) in poss.into_iter().zip(indices.into_iter()) {
let colors = vec![[0.; 4]; poss.len()];
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
// Add 4 vertices, each with its own position attribute (coordinate in
// 3D space), for each of the corners of the parallelogram.
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, poss)
.with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone())
// .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_indices(Indices::U32(indices));
let colors = vec![[0.; 4]; poss.len()];
let mut mesh = Mesh::new(
PrimitiveTopology::TriangleList,
RenderAssetUsages::default(),
)
// Add 4 vertices, each with its own position attribute (coordinate in
// 3D space), for each of the corners of the parallelogram.
.with_inserted_attribute(Mesh::ATTRIBUTE_POSITION, poss)
.with_inserted_attribute(Mesh::ATTRIBUTE_COLOR, colors.clone())
// .with_inserted_attribute(Mesh::ATTRIBUTE_NORMAL, normals)
.with_inserted_indices(Indices::U32(indices));
mesh.compute_smooth_normals();
mesh.compute_smooth_normals();
let mut cells_entities = Vec::with_capacity(cells.len());
cmds.spawn((
Mesh3d(meshes.add(mesh)),
// StandardMaterial
// MeshMaterial3d(materials.add(StandardMaterial::default())),
MeshMaterial3d(materials.add(CellMaterial {
base: StandardMaterial::default(),
extension: CellMaterialExtension {},
})),
Transform::default(),
MapMeshColors(colors),
MeshNeedsUpdate(true),
MapMarker,
));
for cell in cells {
let kind = cell.kind;
let mut cmd = cmds.spawn(cell);
match kind {
CellKind::Grass | CellKind::Forest => {
cmd.insert((
Wealth(0),
Regeneration {
last_update: Duration::ZERO,
full_growth_duration: kind.regen_full_growth_duration(),
},
));
}
_ => {}
}
cmd.observe(self::cells::on_click);
cells_entities.push(cmd.id());
cmds.spawn((
Mesh3d(meshes.add(mesh)),
// StandardMaterial
// MeshMaterial3d(materials.add(StandardMaterial::default())),
MeshMaterial3d(materials.add(CellMaterial {
base: StandardMaterial {
alpha_mode: AlphaMode::Mask(0.5),
..Default::default()
},
extension: CellMaterialExtension {},
})),
Transform::default(),
MeshColors(colors),
MeshNeedsUpdate(true),
MapMarker,
));
}
cmds.insert_resource(Voronoi(voronoi));
cmds.insert_resource(CellsEntities(cells_entities));
}
// TODO: update this to take chunks into account
fn update_map_mesh(
cells: Query<(&Cell, Option<&Wealth>)>,
mut map: Query<(&Mesh3d, &mut MapMeshColors, &mut MeshNeedsUpdate), With<MapMarker>>,
mut map: Query<(&Mesh3d, &mut MeshColors, &mut MeshNeedsUpdate), With<MapMarker>>,
mut meshes: ResMut<Assets<Mesh>>,
) {
let (mesh, mut cols, mut needs_update) = map.single_mut();

View File

@ -7,7 +7,7 @@ use crate::{time::GameTime, ui::CurrentAction};
use super::{
animals::Animal, AnimalKind, CellsEntities, MapMarker, MeshNeedsUpdate, Voronoi,
AVERAGE_NEIGHBORS_NUMBER, CELL_AREA,
AVERAGE_NEIGHBORS_NUMBER, CELLS_PER_CHUNK, CELL_AREA,
};
pub mod material;
@ -59,7 +59,7 @@ pub struct Cell {
pub vertices: Vec<usize>,
}
impl Cell {
pub fn color(&self, wealth: u8) -> [f32; 4] {
pub const fn color(&self, wealth: u8) -> [f32; 4] {
match self.kind {
CellKind::Sea => [0., 0., 1., 1.],
CellKind::Beach => [0.82, 0.84, 0.51, 1.],
@ -79,8 +79,20 @@ impl Cell {
],
}
}
pub const fn chunk_from_id(id: usize) -> usize {
id / CELLS_PER_CHUNK
}
pub const fn chunk(&self) -> usize {
Self::chunk_from_id(self.voronoi_id)
}
}
// #[derive(Component)]
// /// Cell that's in another chunk but needs to be there to form a triangle
// pub struct GhostCell {
// pub chunk:
// };
#[derive(Component)]
pub struct Wealth(pub u8);