|
|
|
@ -2,53 +2,65 @@ use bevy::prelude::*; |
|
|
|
|
use rand::prelude::*; |
|
|
|
|
|
|
|
|
|
use crate::{ |
|
|
|
|
bloxel::{prelude::*, storage::ChunkedOctree}, |
|
|
|
|
bloxel::{ |
|
|
|
|
prelude::*, |
|
|
|
|
storage::{ChunkedOctree, OctreeNode}, |
|
|
|
|
}, |
|
|
|
|
camera_controller::ControlledCamera, |
|
|
|
|
TerrainBlocks, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
pub fn create_chunks_around_camera( |
|
|
|
|
pub struct WorldGenPlugin; |
|
|
|
|
|
|
|
|
|
impl Plugin for WorldGenPlugin { |
|
|
|
|
fn build(&self, app: &mut App) { |
|
|
|
|
app.init_resource::<ExistingChunks>() |
|
|
|
|
.add_systems(Update, (create_chunks_around_camera, generate_terrain)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
fn create_chunks_around_camera( |
|
|
|
|
mut commands: Commands, |
|
|
|
|
mut octree: Local<GeneratedChunks>, |
|
|
|
|
mut octree: ResMut<ExistingChunks>, |
|
|
|
|
camera: Single<&Transform, With<ControlledCamera>>, |
|
|
|
|
chunk_map: Single<Entity, With<ChunkMap>>, |
|
|
|
|
) { |
|
|
|
|
let block_pos = camera.translation.as_ivec3().into(); |
|
|
|
|
let (chunk_pos, _) = ChunkPos::from_block_pos(block_pos); |
|
|
|
|
|
|
|
|
|
let mut create_chunk = |octree: &mut GeneratedChunks, chunk_pos: ChunkPos| { |
|
|
|
|
let mut create_chunk = |octree: &mut ExistingChunks, chunk_pos: ChunkPos| { |
|
|
|
|
commands.entity(*chunk_map).with_child((Chunk, chunk_pos)); |
|
|
|
|
octree.update(chunk_pos, |_node, children, parent| { |
|
|
|
|
octree.update(chunk_pos, |_, children, parent| { |
|
|
|
|
let children = children.map(|a| a.as_slice()).unwrap_or_default(); |
|
|
|
|
*parent = if children.iter().all(|c| *c == Generated::All) { |
|
|
|
|
Generated::All |
|
|
|
|
*parent = if children.iter().all(|c| *c == Existing::All) { |
|
|
|
|
Existing::All |
|
|
|
|
} else { |
|
|
|
|
Generated::Some |
|
|
|
|
Existing::Some |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
// Create chunk at camera's position, if it's not already. This is necessary because we
|
|
|
|
|
// need to "seed" the octree with a region so we have something to begin the search from.
|
|
|
|
|
if octree.get(chunk_pos) == Generated::None { |
|
|
|
|
if octree.get(chunk_pos) == Existing::None { |
|
|
|
|
create_chunk(&mut octree, chunk_pos); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
let to_generate = octree |
|
|
|
|
.find(|node, generated| { |
|
|
|
|
(generated != Generated::All).then(|| -node.region().distance_to_squared(chunk_pos)) |
|
|
|
|
let to_create = octree |
|
|
|
|
.find(|node, exist| { |
|
|
|
|
(exist != Existing::All).then(|| -node.region().distance_to_squared(chunk_pos)) |
|
|
|
|
}) |
|
|
|
|
.take_while(|(_, _, neg_sqr_distance)| *neg_sqr_distance > -(16 * 16)) |
|
|
|
|
.take_while(|(_, _, neg_sqr_distance)| *neg_sqr_distance > -(12 * 12)) |
|
|
|
|
.map(|(chunk_pos, _, _)| chunk_pos) |
|
|
|
|
.take(12) // Generate up to 12 chunks per system iteration.
|
|
|
|
|
.take(12) // Create up to 12 chunks per system iteration.
|
|
|
|
|
.collect::<Vec<_>>(); |
|
|
|
|
|
|
|
|
|
for chunk_pos in to_generate { |
|
|
|
|
for chunk_pos in to_create { |
|
|
|
|
create_chunk(&mut octree, chunk_pos); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
pub fn generate_terrain( |
|
|
|
|
fn generate_terrain( |
|
|
|
|
mut commands: Commands, |
|
|
|
|
terrain_blocks: Option<Res<TerrainBlocks>>, |
|
|
|
|
chunks_without_data: Query<(Entity, &ChunkPos), (With<Chunk>, Without<ChunkData>)>, |
|
|
|
@ -80,12 +92,12 @@ pub fn generate_terrain( |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Deref, DerefMut)] |
|
|
|
|
pub struct GeneratedChunks { |
|
|
|
|
octree: ChunkedOctree<Generated>, |
|
|
|
|
#[derive(Resource, Deref, DerefMut)] |
|
|
|
|
pub struct ExistingChunks { |
|
|
|
|
octree: ChunkedOctree<Existing>, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
impl Default for GeneratedChunks { |
|
|
|
|
impl Default for ExistingChunks { |
|
|
|
|
fn default() -> Self { |
|
|
|
|
let octree = ChunkedOctree::new(5); |
|
|
|
|
Self { octree } |
|
|
|
@ -93,7 +105,7 @@ impl Default for GeneratedChunks { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug)] |
|
|
|
|
pub enum Generated { |
|
|
|
|
pub enum Existing { |
|
|
|
|
#[default] |
|
|
|
|
None, |
|
|
|
|
Some, |
|
|
|
|