From f491739ee821a6ee31ab7f6009243553d63a4f95 Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Thu, 30 May 2024 22:28:22 -0400 Subject: [PATCH] terrain modification improved responsiveness of terrain edits added hexselect methods add create crater function --- engine/world_generation/src/hex_utils.rs | 44 ++++++++- engine/world_generation/src/lib.rs | 91 ++++++++++++++++++- game/main/src/map_rendering/chunk_rebuild.rs | 2 +- .../src/map_rendering/terraforming_test.rs | 26 ++---- 4 files changed, 142 insertions(+), 21 deletions(-) diff --git a/engine/world_generation/src/hex_utils.rs b/engine/world_generation/src/hex_utils.rs index 4f1cc33..c959c1f 100644 --- a/engine/world_generation/src/hex_utils.rs +++ b/engine/world_generation/src/hex_utils.rs @@ -52,7 +52,7 @@ pub fn tile_to_world_distance(dist: u32) -> f32 { return dist as f32 * (2. * INNER_RADIUS); } -pub fn get_tile_count(radius: u32) -> u32 { +pub fn get_tile_count(radius: usize) -> usize { return 1 + 3 * (radius + 1) * radius; } @@ -220,4 +220,46 @@ impl HexCoord { self.get_neighbor(5), ]; } + + pub fn hex_select(&self, radius: usize, include_center: bool) -> Vec { + assert!(radius != 0, "Radius cannot be zero"); + let mut result = Vec::with_capacity(get_tile_count(radius)); + + if include_center { + result.push(*self); + } + + for k in 0..(radius + 1) { + let mut p = self.scale(4, k); + for i in 0..6 { + for _j in 0..k { + p = p.get_neighbor(i); + result.push(p); + } + } + } + + return result; + } + + pub fn select_ring(&self, radius: usize) -> Vec { + assert!(radius != 0, "Radius cannot be zero"); + let mut result = Vec::with_capacity(radius * 6); + + let mut p = self.scale(4, radius); + + if radius == 1 { + result.push(*self); + return result; + } + + for i in 0..6 { + for _j in 0..radius { + result.push(p); + p = p.get_neighbor(i); + } + } + + return result; + } } diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index d5edb9f..dc2fa4b 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -8,7 +8,7 @@ pub mod tile_manager; pub mod tile_mapper; pub mod prelude { - use crate::hex_utils::{HexCoord, INNER_RADIUS, OUTER_RADIUS, SHORT_DIAGONAL}; + use crate::hex_utils::{get_tile_count, HexCoord, INNER_RADIUS, OUTER_RADIUS, SHORT_DIAGONAL}; use bevy::math::{IVec2, UVec2, Vec2, Vec3}; use bevy::prelude::Resource; use bevy::prelude::*; @@ -205,6 +205,11 @@ pub mod prelude { return chunk.heights[pos.to_chunk_local_index()]; } + pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32 { + let chunk = &mut self.chunks[pos.to_chunk_index(self.width)]; + return &mut chunk.heights[pos.to_chunk_local_index()]; + } + pub fn is_in_bounds(&self, pos: &HexCoord) -> bool { return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE); } @@ -239,6 +244,90 @@ pub mod prelude { pub fn set_height(&mut self, pos: &HexCoord, height: f32) { self.chunks[pos.to_chunk_index(self.width)].heights[pos.to_chunk_local_index()] = height; } + + pub fn create_crater(&mut self, pos: &HexCoord, radius: usize, depth: f32) -> Vec { + assert!(radius != 0, "Radius cannot be zero"); + let width = self.width; + + let mut chunks = self.hex_select_mut(pos, radius, true, |h, r| { + let d = (r as f32) / (radius as f32); + let cur = h.clone(); + let h2 = cur - depth; + *h = h2.lerp(cur, d * d); + + return pos.to_chunk_index(width); + }); + + chunks.dedup(); + + return chunks; + } + + pub fn hex_select( + &mut self, + center: &HexCoord, + radius: usize, + include_center: bool, + op: OP, + ) -> Vec + where + OP: Fn(f32, usize) -> Ret + Sync + Send, + { + assert!(radius != 0, "Radius cannot be zero"); + + if include_center { + let h = self.sample_height(center); + (op)(h, 0); + } + + let mut result = Vec::with_capacity(get_tile_count(radius)); + + for k in 0..(radius + 1) { + let mut p = center.scale(4, k); + for i in 0..6 { + for _j in 0..k { + p = p.get_neighbor(i); + let h = self.sample_height(&p); + result.push((op)(h, k)); + } + } + } + + return result; + } + + pub fn hex_select_mut( + &mut self, + center: &HexCoord, + radius: usize, + include_center: bool, + op: OP, + ) -> Vec + where + OP: Fn(&mut f32, usize) -> Ret + Sync + Send, + { + assert!(radius != 0, "Radius cannot be zero"); + + if include_center { + let h = self.sample_height_mut(center); + (op)(h, 0); + } + + let mut result = Vec::with_capacity(get_tile_count(radius)); + + for k in 0..(radius + 1) { + let mut p = center.scale(4, k); + for i in 0..6 { + for _j in 0..k { + p = p.get_neighbor(i); + let h = self.sample_height_mut(&p); + result.push((op)(h, k)); + } + } + } + + return result; + } } pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute = MeshVertexAttribute::new("PackedVertexData", 988540817, VertexFormat::Uint32); diff --git a/game/main/src/map_rendering/chunk_rebuild.rs b/game/main/src/map_rendering/chunk_rebuild.rs index ef1c7e6..2ae8ea1 100644 --- a/game/main/src/map_rendering/chunk_rebuild.rs +++ b/game/main/src/map_rendering/chunk_rebuild.rs @@ -30,7 +30,7 @@ pub struct ChunkRebuildQueue { fn chunk_rebuilder( mut commands: Commands, - chunk_query: Query<(Entity, &PhosChunk), With>, + chunk_query: Query<(Entity, &PhosChunk), (With, Without)>, heightmap: Res, ) { let pool = AsyncComputeTaskPool::get(); diff --git a/game/main/src/map_rendering/terraforming_test.rs b/game/main/src/map_rendering/terraforming_test.rs index e58a908..21103a4 100644 --- a/game/main/src/map_rendering/terraforming_test.rs +++ b/game/main/src/map_rendering/terraforming_test.rs @@ -7,8 +7,6 @@ use crate::{ prelude::{PhosChunkRegistry, RebuildChunk}, }; -use super::chunk_rebuild::ChunkRebuildQueue; - pub struct TerraFormingTestPlugin; impl Plugin for TerraFormingTestPlugin { @@ -25,12 +23,11 @@ fn deform( rapier_context: Res, mut heightmap: ResMut, chunks: Res, - time: Res