refactoring hex coords
This commit is contained in:
17
Cargo.lock
generated
17
Cargo.lock
generated
@@ -445,9 +445,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bevy"
|
name = "bevy"
|
||||||
version = "0.18.0"
|
version = "0.18.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ec689b5a79452b6f777b889bbff22d3216b82a8d2ab7814d4a0eb571e9938d97"
|
checksum = "1fd310426290cec560221f9750c2f4484be4a8eeea7de3483c423329b465c40e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy_internal",
|
"bevy_internal",
|
||||||
"tracing",
|
"tracing",
|
||||||
@@ -1993,6 +1993,7 @@ dependencies = [
|
|||||||
"bevy",
|
"bevy",
|
||||||
"bevy_asset_loader",
|
"bevy_asset_loader",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
|
"hex",
|
||||||
"ron 0.12.0",
|
"ron 0.12.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
@@ -3493,6 +3494,14 @@ version = "0.5.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hex"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bevy",
|
||||||
|
"serde",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hexasphere"
|
name = "hexasphere"
|
||||||
version = "16.0.0"
|
version = "16.0.0"
|
||||||
@@ -4933,6 +4942,7 @@ dependencies = [
|
|||||||
"bevy_asset_loader",
|
"bevy_asset_loader",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
"buildings",
|
"buildings",
|
||||||
|
"hex",
|
||||||
"image",
|
"image",
|
||||||
"noise",
|
"noise",
|
||||||
"rayon",
|
"rayon",
|
||||||
@@ -5714,6 +5724,7 @@ name = "shared"
|
|||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bevy",
|
"bevy",
|
||||||
|
"hex",
|
||||||
"serde",
|
"serde",
|
||||||
"world_generation",
|
"world_generation",
|
||||||
]
|
]
|
||||||
@@ -6321,6 +6332,7 @@ dependencies = [
|
|||||||
"bevy",
|
"bevy",
|
||||||
"bevy_asset_loader",
|
"bevy_asset_loader",
|
||||||
"bevy_rapier3d",
|
"bevy_rapier3d",
|
||||||
|
"hex",
|
||||||
"ordered-float",
|
"ordered-float",
|
||||||
"pathfinding",
|
"pathfinding",
|
||||||
"quadtree_rs",
|
"quadtree_rs",
|
||||||
@@ -7515,6 +7527,7 @@ dependencies = [
|
|||||||
"bevy",
|
"bevy",
|
||||||
"bevy-inspector-egui",
|
"bevy-inspector-egui",
|
||||||
"bevy_asset_loader",
|
"bevy_asset_loader",
|
||||||
|
"hex",
|
||||||
"image",
|
"image",
|
||||||
"noise",
|
"noise",
|
||||||
"num 0.4.3",
|
"num 0.4.3",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ members = [
|
|||||||
"engine/world_generation",
|
"engine/world_generation",
|
||||||
"engine/asset_loader",
|
"engine/asset_loader",
|
||||||
"engine/data",
|
"engine/data",
|
||||||
|
"engine/hex",
|
||||||
]
|
]
|
||||||
|
|
||||||
# Enable a small amount of optimization in debug mode
|
# Enable a small amount of optimization in debug mode
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ bevy_asset_loader = { version = "0.25.0", features = [
|
|||||||
ron = "0.12.0"
|
ron = "0.12.0"
|
||||||
image = "0.25.9"
|
image = "0.25.9"
|
||||||
num = "0.4.3"
|
num = "0.4.3"
|
||||||
|
hex = { path = "../hex" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tracing = ["bevy/trace_tracy"]
|
tracing = ["bevy/trace_tracy"]
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use bevy::{mesh::MeshVertexAttribute, prelude::*, render::render_resource::VertexFormat};
|
use bevy::{mesh::MeshVertexAttribute, prelude::*, render::render_resource::VertexFormat};
|
||||||
|
use hex::{INNER_RADIUS, OUTER_RADIUS};
|
||||||
|
|
||||||
use crate::hex_utils::{INNER_RADIUS, OUTER_RADIUS};
|
// use crate::hex_utils::{INNER_RADIUS, OUTER_RADIUS};
|
||||||
|
|
||||||
pub const TEX_MULTI: Vec2 = Vec2::new(1000., 1.);
|
pub const TEX_MULTI: Vec2 = Vec2::new(1000., 1.);
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,22 @@
|
|||||||
use crate::{hex_utils::*, prelude::*};
|
use crate::prelude::*;
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use bevy::log::*;
|
use bevy::log::*;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use hex::prelude::*;
|
||||||
|
|
||||||
const CHUNK_TOTAL: usize = Chunk::SIZE * Chunk::SIZE;
|
const CHUNK_TOTAL: usize = Chunk::SIZE * Chunk::SIZE;
|
||||||
|
|
||||||
pub fn generate_chunk_collider(chunk: &MeshChunkData) -> (Vec<Vec3>, Vec<[u32; 3]>) {
|
pub fn generate_chunk_collider(chunk: &MeshChunkData) -> (Vec<Vec3>, Vec<[u32; 3]>)
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let span = info_span!("generate_chunk_collider").entered();
|
let span = info_span!("generate_chunk_collider").entered();
|
||||||
let vertex_count: usize = CHUNK_TOTAL * 6;
|
let vertex_count: usize = CHUNK_TOTAL * 6;
|
||||||
let mut verts = Vec::with_capacity(vertex_count);
|
let mut verts = Vec::with_capacity(vertex_count);
|
||||||
let mut indices = Vec::with_capacity(vertex_count);
|
let mut indices = Vec::with_capacity(vertex_count);
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let height = chunk.heights[x + z * Chunk::SIZE];
|
let height = chunk.heights[x + z * Chunk::SIZE];
|
||||||
let coord = HexCoord::from_grid_pos(x, z);
|
let coord = HexCoord::from_grid_pos(x, z);
|
||||||
let neighbors = chunk.get_neighbors(&coord);
|
let neighbors = chunk.get_neighbors(&coord);
|
||||||
@@ -24,9 +28,11 @@ pub fn generate_chunk_collider(chunk: &MeshChunkData) -> (Vec<Vec3>, Vec<[u32; 3
|
|||||||
return (verts, indices);
|
return (verts, indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tile_collider(pos: Vec3, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32; 3]>, neighbors: &[f32; 6]) {
|
fn create_tile_collider(pos: Vec3, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32; 3]>, neighbors: &[f32; 6])
|
||||||
|
{
|
||||||
let idx = verts.len() as u32;
|
let idx = verts.len() as u32;
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
let p = pos + HEX_CORNERS[i];
|
let p = pos + HEX_CORNERS[i];
|
||||||
verts.push(p);
|
verts.push(p);
|
||||||
}
|
}
|
||||||
@@ -37,9 +43,11 @@ fn create_tile_collider(pos: Vec3, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32
|
|||||||
indices.push([idx + 2, idx + 4, idx + 5]);
|
indices.push([idx + 2, idx + 4, idx + 5]);
|
||||||
indices.push([idx + 2, idx + 3, idx + 4]);
|
indices.push([idx + 2, idx + 3, idx + 4]);
|
||||||
|
|
||||||
for i in 0..neighbors.len() {
|
for i in 0..neighbors.len()
|
||||||
|
{
|
||||||
let n_height = neighbors[i];
|
let n_height = neighbors[i];
|
||||||
if n_height < pos.y {
|
if n_height < pos.y
|
||||||
|
{
|
||||||
create_tile_wall_collider(
|
create_tile_wall_collider(
|
||||||
idx,
|
idx,
|
||||||
Vec3::new(pos.x, n_height.min(pos.y - OUTER_RADIUS / 2.), pos.z),
|
Vec3::new(pos.x, n_height.min(pos.y - OUTER_RADIUS / 2.), pos.z),
|
||||||
@@ -51,7 +59,8 @@ fn create_tile_collider(pos: Vec3, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_tile_wall_collider(idx: u32, pos: Vec3, dir: usize, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32; 3]>) {
|
fn create_tile_wall_collider(idx: u32, pos: Vec3, dir: usize, verts: &mut Vec<Vec3>, indices: &mut Vec<[u32; 3]>)
|
||||||
|
{
|
||||||
let idx2 = verts.len() as u32;
|
let idx2 = verts.len() as u32;
|
||||||
|
|
||||||
verts.push(pos + HEX_CORNERS[(dir) % 6]);
|
verts.push(pos + HEX_CORNERS[(dir) % 6]);
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::hex_utils::HexCoord;
|
use crate::prelude::*;
|
||||||
use crate::{hex_utils::offset3d_to_world, prelude::*};
|
|
||||||
use bevy::asset::RenderAssetUsages;
|
use bevy::asset::RenderAssetUsages;
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
use bevy::log::*;
|
use bevy::log::*;
|
||||||
use bevy::mesh::{Indices, PrimitiveTopology};
|
use bevy::mesh::{Indices, PrimitiveTopology};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use hex::prelude::*;
|
||||||
|
|
||||||
pub fn generate_chunk_mesh(chunk: &MeshChunkData) -> Mesh {
|
pub fn generate_chunk_mesh(chunk: &MeshChunkData) -> Mesh
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let span = info_span!("generate_chunk_mesh").entered();
|
let span = info_span!("generate_chunk_mesh").entered();
|
||||||
|
|
||||||
@@ -16,8 +17,10 @@ pub fn generate_chunk_mesh(chunk: &MeshChunkData) -> Mesh {
|
|||||||
let mut indices = Vec::with_capacity(vertex_count);
|
let mut indices = Vec::with_capacity(vertex_count);
|
||||||
let mut normals = Vec::with_capacity(vertex_count);
|
let mut normals = Vec::with_capacity(vertex_count);
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let idx = x + z * Chunk::SIZE;
|
let idx = x + z * Chunk::SIZE;
|
||||||
let height = chunk.heights[idx];
|
let height = chunk.heights[idx];
|
||||||
let off_pos = Vec3::new(x as f32, height, z as f32);
|
let off_pos = Vec3::new(x as f32, height, z as f32);
|
||||||
@@ -59,20 +62,23 @@ fn create_tile(
|
|||||||
normals: &mut Vec<Vec3>,
|
normals: &mut Vec<Vec3>,
|
||||||
texture_index: u32,
|
texture_index: u32,
|
||||||
side_texture_index: u32,
|
side_texture_index: u32,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
let uv_offset = Vec2::splat(0.5);
|
let uv_offset = Vec2::splat(0.5);
|
||||||
let tex_off = Vec2::new(texture_index as f32, 0.);
|
let tex_off = Vec2::new(texture_index as f32, 0.);
|
||||||
let side_tex_off = Vec2::new(side_texture_index as f32, 0.);
|
let side_tex_off = Vec2::new(side_texture_index as f32, 0.);
|
||||||
|
|
||||||
let idx = verts.len() as u32;
|
let idx = verts.len() as u32;
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
let p = pos + HEX_CORNERS[i];
|
let p = pos + HEX_CORNERS[i];
|
||||||
verts.push(p);
|
verts.push(p);
|
||||||
let uv = (HEX_CORNERS[i].xz() / 2.) + uv_offset;
|
let uv = (HEX_CORNERS[i].xz() / 2.) + uv_offset;
|
||||||
uvs.push((uv / TEX_MULTI) + tex_off);
|
uvs.push((uv / TEX_MULTI) + tex_off);
|
||||||
normals.push(Vec3::Y);
|
normals.push(Vec3::Y);
|
||||||
}
|
}
|
||||||
for i in 0..3 {
|
for i in 0..3
|
||||||
|
{
|
||||||
let off = i * 2;
|
let off = i * 2;
|
||||||
indices.push(off + idx);
|
indices.push(off + idx);
|
||||||
indices.push(((off + 1) % 6) + idx);
|
indices.push(((off + 1) % 6) + idx);
|
||||||
@@ -82,15 +88,19 @@ fn create_tile(
|
|||||||
indices.push(idx + 2);
|
indices.push(idx + 2);
|
||||||
indices.push(idx + 4);
|
indices.push(idx + 4);
|
||||||
|
|
||||||
for i in 0..neighbors.len() {
|
for i in 0..neighbors.len()
|
||||||
|
{
|
||||||
let n_height = neighbors[i];
|
let n_height = neighbors[i];
|
||||||
if n_height < pos.y {
|
if n_height < pos.y
|
||||||
|
{
|
||||||
create_tile_wall(pos, i, n_height, verts, uvs, indices, normals, side_tex_off);
|
create_tile_wall(pos, i, n_height, verts, uvs, indices, normals, side_tex_off);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width: usize, map_height: usize) -> Mesh {
|
#[allow(unused)]
|
||||||
|
pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width: usize, map_height: usize) -> Mesh
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _gen_mesh = info_span!("Generate Water Surface Mesh").entered();
|
let _gen_mesh = info_span!("Generate Water Surface Mesh").entered();
|
||||||
let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 7;
|
let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 7;
|
||||||
@@ -99,11 +109,14 @@ pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width
|
|||||||
let mut indices = Vec::with_capacity(vertex_count);
|
let mut indices = Vec::with_capacity(vertex_count);
|
||||||
let mut normals = Vec::with_capacity(vertex_count);
|
let mut normals = Vec::with_capacity(vertex_count);
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let idx = x + z * Chunk::SIZE;
|
let idx = x + z * Chunk::SIZE;
|
||||||
let height = chunk.heights[idx];
|
let height = chunk.heights[idx];
|
||||||
if height > sealevel {
|
if height > sealevel
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let off_pos = Vec3::new(x as f32, sealevel, z as f32);
|
let off_pos = Vec3::new(x as f32, sealevel, z as f32);
|
||||||
@@ -143,8 +156,10 @@ fn create_tile_water_surface(
|
|||||||
uvs: &mut Vec<Vec2>,
|
uvs: &mut Vec<Vec2>,
|
||||||
indices: &mut Vec<u32>,
|
indices: &mut Vec<u32>,
|
||||||
normals: &mut Vec<Vec3>,
|
normals: &mut Vec<Vec3>,
|
||||||
) {
|
)
|
||||||
if !neighbor_has_land {
|
{
|
||||||
|
if !neighbor_has_land
|
||||||
|
{
|
||||||
crate_tile_water_inner_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals);
|
crate_tile_water_inner_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -159,23 +174,29 @@ fn crate_tile_water_inner_surface(
|
|||||||
uvs: &mut Vec<Vec2>,
|
uvs: &mut Vec<Vec2>,
|
||||||
indices: &mut Vec<u32>,
|
indices: &mut Vec<u32>,
|
||||||
normals: &mut Vec<Vec3>,
|
normals: &mut Vec<Vec3>,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
//todo: share verts
|
//todo: share verts
|
||||||
let idx = verts.len() as u32;
|
let idx = verts.len() as u32;
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
let p = pos + HEX_CORNERS[i];
|
let p = pos + HEX_CORNERS[i];
|
||||||
verts.push(p);
|
verts.push(p);
|
||||||
let n1 = if let Some(v) = neighbors[i].1 { v } else { dist_to_land };
|
let n1 = if let Some(v) = neighbors[i].1 { v } else { dist_to_land };
|
||||||
let n2 = if let Some(v) = neighbors[(i + 5) % 6].1 {
|
let n2 = if let Some(v) = neighbors[(i + 5) % 6].1
|
||||||
|
{
|
||||||
v
|
v
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dist_to_land
|
dist_to_land
|
||||||
};
|
};
|
||||||
let d = (n1 + n2 + dist_to_land) / 3.0;
|
let d = (n1 + n2 + dist_to_land) / 3.0;
|
||||||
uvs.push(Vec2::new(0.0, d.remap(0., 4., 1.0, 0.0)));
|
uvs.push(Vec2::new(0.0, d.remap(0., 4., 1.0, 0.0)));
|
||||||
normals.push(Vec3::Y);
|
normals.push(Vec3::Y);
|
||||||
}
|
}
|
||||||
for i in 0..3 {
|
for i in 0..3
|
||||||
|
{
|
||||||
let off = i * 2;
|
let off = i * 2;
|
||||||
indices.push(off + idx);
|
indices.push(off + idx);
|
||||||
indices.push(((off + 1) % 6) + idx);
|
indices.push(((off + 1) % 6) + idx);
|
||||||
@@ -194,13 +215,15 @@ fn crate_tile_water_shore_surface(
|
|||||||
uvs: &mut Vec<Vec2>,
|
uvs: &mut Vec<Vec2>,
|
||||||
indices: &mut Vec<u32>,
|
indices: &mut Vec<u32>,
|
||||||
normals: &mut Vec<Vec3>,
|
normals: &mut Vec<Vec3>,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
let idx = verts.len() as u32;
|
let idx = verts.len() as u32;
|
||||||
//todo: only use triangle fan when on shoreline
|
//todo: only use triangle fan when on shoreline
|
||||||
verts.push(pos);
|
verts.push(pos);
|
||||||
uvs.push(Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0)));
|
uvs.push(Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0)));
|
||||||
normals.push(Vec3::Y);
|
normals.push(Vec3::Y);
|
||||||
for i in 0..12 {
|
for i in 0..12
|
||||||
|
{
|
||||||
let p = pos + WATER_HEX_CORNERS[i];
|
let p = pos + WATER_HEX_CORNERS[i];
|
||||||
verts.push(p);
|
verts.push(p);
|
||||||
let ni = i / 2;
|
let ni = i / 2;
|
||||||
@@ -208,16 +231,21 @@ fn crate_tile_water_shore_surface(
|
|||||||
let nn = neighbors[(ni + 5) % 6];
|
let nn = neighbors[(ni + 5) % 6];
|
||||||
let mut uv = Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0));
|
let mut uv = Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0));
|
||||||
|
|
||||||
if nn.0 > pos.y || n.0 > pos.y {
|
if nn.0 > pos.y || n.0 > pos.y
|
||||||
|
{
|
||||||
uv.x = 1.0;
|
uv.x = 1.0;
|
||||||
}
|
}
|
||||||
if ni * 2 != i {
|
if ni * 2 != i
|
||||||
if n.0 <= pos.y {
|
{
|
||||||
|
if n.0 <= pos.y
|
||||||
|
{
|
||||||
uv.x = 0.0;
|
uv.x = 0.0;
|
||||||
}
|
}
|
||||||
let d = if let Some(v) = n.1 { v } else { dist_to_land };
|
let d = if let Some(v) = n.1 { v } else { dist_to_land };
|
||||||
uv.y = ((d + dist_to_land) / 2.0).remap(0., 4., 1.0, 0.0);
|
uv.y = ((d + dist_to_land) / 2.0).remap(0., 4., 1.0, 0.0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
let d = if let Some(v) = n.1 { v } else { dist_to_land };
|
let d = if let Some(v) = n.1 { v } else { dist_to_land };
|
||||||
let d2 = if let Some(v) = nn.1 { v } else { dist_to_land };
|
let d2 = if let Some(v) = nn.1 { v } else { dist_to_land };
|
||||||
uv.y = ((d + d2 + dist_to_land) / 3.0).remap(0., 4., 1.0, 0.0);
|
uv.y = ((d + d2 + dist_to_land) / 3.0).remap(0., 4., 1.0, 0.0);
|
||||||
@@ -241,7 +269,8 @@ fn create_tile_wall(
|
|||||||
indices: &mut Vec<u32>,
|
indices: &mut Vec<u32>,
|
||||||
normals: &mut Vec<Vec3>,
|
normals: &mut Vec<Vec3>,
|
||||||
tex_off: Vec2,
|
tex_off: Vec2,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
let p1 = HEX_CORNERS[(dir) % 6] + pos;
|
let p1 = HEX_CORNERS[(dir) % 6] + pos;
|
||||||
let p2 = HEX_CORNERS[(dir + 1) % 6] + pos;
|
let p2 = HEX_CORNERS[(dir + 1) % 6] + pos;
|
||||||
let p3 = Vec3::new(p1.x, height, p1.z);
|
let p3 = Vec3::new(p1.x, height, p1.z);
|
||||||
@@ -275,12 +304,14 @@ fn create_tile_wall(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests
|
||||||
|
{
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generate_tile_wall() {
|
fn generate_tile_wall()
|
||||||
|
{
|
||||||
let mut verts = Vec::new();
|
let mut verts = Vec::new();
|
||||||
let mut uvs = Vec::new();
|
let mut uvs = Vec::new();
|
||||||
let mut normals = Vec::new();
|
let mut normals = Vec::new();
|
||||||
@@ -307,7 +338,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn generate_tile() {
|
fn generate_tile()
|
||||||
|
{
|
||||||
let mut verts = Vec::new();
|
let mut verts = Vec::new();
|
||||||
let mut uvs = Vec::new();
|
let mut uvs = Vec::new();
|
||||||
let mut normals = Vec::new();
|
let mut normals = Vec::new();
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
use crate::hex_utils::HexCoord;
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
use bevy::asset::RenderAssetUsages;
|
use bevy::asset::RenderAssetUsages;
|
||||||
use bevy::{
|
use bevy::{
|
||||||
mesh::{Indices, PrimitiveTopology},
|
mesh::{Indices, PrimitiveTopology},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
use hex::prelude::*;
|
||||||
|
|
||||||
pub fn generate_packed_chunk_mesh(chunk: &MeshChunkData) -> Mesh {
|
pub fn generate_packed_chunk_mesh(chunk: &MeshChunkData) -> Mesh
|
||||||
|
{
|
||||||
let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6;
|
let vertex_count: usize = Chunk::SIZE * Chunk::SIZE * 6;
|
||||||
let mut packed_data = Vec::with_capacity(vertex_count);
|
let mut packed_data = Vec::with_capacity(vertex_count);
|
||||||
let mut indices = Vec::with_capacity(vertex_count);
|
let mut indices = Vec::with_capacity(vertex_count);
|
||||||
let mut heights = Vec::with_capacity(vertex_count);
|
let mut heights = Vec::with_capacity(vertex_count);
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let idx = x + z * Chunk::SIZE;
|
let idx = x + z * Chunk::SIZE;
|
||||||
let height = chunk.heights[idx];
|
let height = chunk.heights[idx];
|
||||||
let coord = HexCoord::from_grid_pos(x, z);
|
let coord = HexCoord::from_grid_pos(x, z);
|
||||||
@@ -51,12 +54,14 @@ fn create_packed_tile(
|
|||||||
heights: &mut Vec<f32>,
|
heights: &mut Vec<f32>,
|
||||||
texture_index: u32,
|
texture_index: u32,
|
||||||
side_texture_index: u32,
|
side_texture_index: u32,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
let idx = packed_data.len() as u32;
|
let idx = packed_data.len() as u32;
|
||||||
|
|
||||||
packed_data.push(pack_vertex_data(offset, 0, texture_index));
|
packed_data.push(pack_vertex_data(offset, 0, texture_index));
|
||||||
heights.push(height);
|
heights.push(height);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
packed_data.push(pack_vertex_data(offset, i + 1, texture_index));
|
packed_data.push(pack_vertex_data(offset, i + 1, texture_index));
|
||||||
indices.push(idx);
|
indices.push(idx);
|
||||||
indices.push(idx + 1 + i as u32);
|
indices.push(idx + 1 + i as u32);
|
||||||
@@ -64,9 +69,11 @@ fn create_packed_tile(
|
|||||||
heights.push(height);
|
heights.push(height);
|
||||||
}
|
}
|
||||||
|
|
||||||
for i in 0..neighbors.len() {
|
for i in 0..neighbors.len()
|
||||||
|
{
|
||||||
let n_height = neighbors[i];
|
let n_height = neighbors[i];
|
||||||
if n_height < height {
|
if n_height < height
|
||||||
|
{
|
||||||
create_packed_tile_wall(
|
create_packed_tile_wall(
|
||||||
offset,
|
offset,
|
||||||
height,
|
height,
|
||||||
@@ -90,7 +97,8 @@ fn create_packed_tile_wall(
|
|||||||
indices: &mut Vec<u32>,
|
indices: &mut Vec<u32>,
|
||||||
heights: &mut Vec<f32>,
|
heights: &mut Vec<f32>,
|
||||||
side_texture_index: u32,
|
side_texture_index: u32,
|
||||||
) {
|
)
|
||||||
|
{
|
||||||
let idx = packed_data.len() as u32;
|
let idx = packed_data.len() as u32;
|
||||||
|
|
||||||
let side_2 = ((side + 1) % 6) + 1;
|
let side_2 = ((side + 1) % 6) + 1;
|
||||||
@@ -113,7 +121,8 @@ fn create_packed_tile_wall(
|
|||||||
indices.push(idx + 3);
|
indices.push(idx + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_vertex_data(offset: UVec2, vert: usize, tex: u32) -> u32 {
|
fn pack_vertex_data(offset: UVec2, vert: usize, tex: u32) -> u32
|
||||||
|
{
|
||||||
//6 + 6 bits offset
|
//6 + 6 bits offset
|
||||||
//4 bits vert
|
//4 bits vert
|
||||||
//12 bits texture
|
//12 bits texture
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use core::f32;
|
|||||||
use bevy::math::{IVec2, UVec2};
|
use bevy::math::{IVec2, UVec2};
|
||||||
use bevy::prelude::{FloatExt, Vec2};
|
use bevy::prelude::{FloatExt, Vec2};
|
||||||
use bevy::utils::default;
|
use bevy::utils::default;
|
||||||
|
use hex::prelude::*;
|
||||||
use noise::{NoiseFn, Simplex, SuperSimplex};
|
use noise::{NoiseFn, Simplex, SuperSimplex};
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
@@ -10,7 +11,8 @@ use crate::biome_painter::BiomePainter;
|
|||||||
use crate::map::biome_map::{BiomeChunk, BiomeData, BiomeMap};
|
use crate::map::biome_map::{BiomeChunk, BiomeData, BiomeMap};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> (Map, BiomeMap) {
|
pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePainter) -> (Map, BiomeMap)
|
||||||
|
{
|
||||||
let biomes = generate_biomes(cfg, seed, painter);
|
let biomes = generate_biomes(cfg, seed, painter);
|
||||||
let biomes_borrow = &biomes;
|
let biomes_borrow = &biomes;
|
||||||
// let mut chunks: Vec<Chunk> = Vec::with_capacity(cfg.size.length_squared() as usize);
|
// let mut chunks: Vec<Chunk> = Vec::with_capacity(cfg.size.length_squared() as usize);
|
||||||
@@ -25,11 +27,14 @@ pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePain
|
|||||||
.collect();
|
.collect();
|
||||||
let mut min = f32::MAX;
|
let mut min = f32::MAX;
|
||||||
let mut max = f32::MIN;
|
let mut max = f32::MIN;
|
||||||
for chunk in &chunks {
|
for chunk in &chunks
|
||||||
if chunk.min_level < min {
|
{
|
||||||
|
if chunk.min_level < min
|
||||||
|
{
|
||||||
min = chunk.min_level;
|
min = chunk.min_level;
|
||||||
}
|
}
|
||||||
if chunk.max_level > max {
|
if chunk.max_level > max
|
||||||
|
{
|
||||||
max = chunk.max_level;
|
max = chunk.max_level;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +53,8 @@ pub fn generate_heightmap(cfg: &GenerationConfig, seed: u32, painter: &BiomePain
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_biomes(cfg: &GenerationConfig, seed: u32, biome_painter: &BiomePainter) -> BiomeMap {
|
pub fn generate_biomes(cfg: &GenerationConfig, seed: u32, biome_painter: &BiomePainter) -> BiomeMap
|
||||||
|
{
|
||||||
let mut map = BiomeMap::new(cfg.size, biome_painter.biomes.len());
|
let mut map = BiomeMap::new(cfg.size, biome_painter.biomes.len());
|
||||||
map.chunks = (0..cfg.size.y)
|
map.chunks = (0..cfg.size.y)
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
@@ -68,7 +74,8 @@ pub fn generate_biome_chunk(
|
|||||||
cfg: &GenerationConfig,
|
cfg: &GenerationConfig,
|
||||||
seed: u32,
|
seed: u32,
|
||||||
biome_painter: &BiomePainter,
|
biome_painter: &BiomePainter,
|
||||||
) -> BiomeChunk {
|
) -> BiomeChunk
|
||||||
|
{
|
||||||
let mut chunk = BiomeChunk {
|
let mut chunk = BiomeChunk {
|
||||||
offset: UVec2::new(chunk_x as u32, chunk_y as u32),
|
offset: UVec2::new(chunk_x as u32, chunk_y as u32),
|
||||||
data: [BiomeData::default(); Chunk::AREA],
|
data: [BiomeData::default(); Chunk::AREA],
|
||||||
@@ -78,8 +85,10 @@ pub fn generate_biome_chunk(
|
|||||||
let noise_t = Simplex::new(seed + 2);
|
let noise_t = Simplex::new(seed + 2);
|
||||||
let noise_c = Simplex::new(seed + 3);
|
let noise_c = Simplex::new(seed + 3);
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let moisture = sample_point(
|
let moisture = sample_point(
|
||||||
x as f64 + chunk_x as f64 * Chunk::SIZE as f64,
|
x as f64 + chunk_x as f64 * Chunk::SIZE as f64,
|
||||||
z as f64 + chunk_y as f64 * Chunk::SIZE as f64,
|
z as f64 + chunk_y as f64 * Chunk::SIZE as f64,
|
||||||
@@ -123,14 +132,16 @@ pub fn generate_biome_chunk(
|
|||||||
return chunk;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_noise_map(size: UVec2, seed: u32, cfg: &NoiseConfig, border_size: f32) -> Vec<f32> {
|
pub fn generate_noise_map(size: UVec2, seed: u32, cfg: &NoiseConfig, border_size: f32) -> Vec<f32>
|
||||||
|
{
|
||||||
let noise = SuperSimplex::new(seed);
|
let noise = SuperSimplex::new(seed);
|
||||||
|
|
||||||
let data: Vec<_> = (0..(size.y as usize * Chunk::SIZE))
|
let data: Vec<_> = (0..(size.y as usize * Chunk::SIZE))
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.flat_map(|y| {
|
.flat_map(|y| {
|
||||||
let mut row = Vec::with_capacity(size.x as usize * Chunk::SIZE);
|
let mut row = Vec::with_capacity(size.x as usize * Chunk::SIZE);
|
||||||
for x in 0..row.capacity() {
|
for x in 0..row.capacity()
|
||||||
|
{
|
||||||
row.push(sample_point(
|
row.push(sample_point(
|
||||||
x as f64,
|
x as f64,
|
||||||
y as f64,
|
y as f64,
|
||||||
@@ -154,21 +165,26 @@ pub fn generate_chunk(
|
|||||||
seed: u32,
|
seed: u32,
|
||||||
biome_chunk: &BiomeChunk,
|
biome_chunk: &BiomeChunk,
|
||||||
biome_painter: &BiomePainter,
|
biome_painter: &BiomePainter,
|
||||||
) -> Chunk {
|
) -> Chunk
|
||||||
|
{
|
||||||
let mut result: [f32; Chunk::SIZE * Chunk::SIZE] = [0.; Chunk::AREA];
|
let mut result: [f32; Chunk::SIZE * Chunk::SIZE] = [0.; Chunk::AREA];
|
||||||
let mut data = [BiomeData::default(); Chunk::AREA];
|
let mut data = [BiomeData::default(); Chunk::AREA];
|
||||||
let mut biome_ids = [0; Chunk::AREA];
|
let mut biome_ids = [0; Chunk::AREA];
|
||||||
let noise = Simplex::new(seed);
|
let noise = Simplex::new(seed);
|
||||||
let mut min = f32::MAX;
|
let mut min = f32::MAX;
|
||||||
let mut max = f32::MIN;
|
let mut max = f32::MIN;
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let biome_data = biome_chunk.get_biome_data(x, z);
|
let biome_data = biome_chunk.get_biome_data(x, z);
|
||||||
let biome_blend = biome_chunk.get_biome(x, z);
|
let biome_blend = biome_chunk.get_biome(x, z);
|
||||||
let mut sample = 0.;
|
let mut sample = 0.;
|
||||||
for i in 0..biome_blend.len() {
|
for i in 0..biome_blend.len()
|
||||||
|
{
|
||||||
let blend = biome_blend[i];
|
let blend = biome_blend[i];
|
||||||
if blend == 0. {
|
if blend == 0.
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let biome = &biome_painter.biomes[i];
|
let biome = &biome_painter.biomes[i];
|
||||||
@@ -185,10 +201,12 @@ pub fn generate_chunk(
|
|||||||
let idx = x + z * Chunk::SIZE;
|
let idx = x + z * Chunk::SIZE;
|
||||||
biome_ids[idx] = biome_chunk.get_biome_id_dithered(x, z, &noise, cfg.biome_dither);
|
biome_ids[idx] = biome_chunk.get_biome_id_dithered(x, z, &noise, cfg.biome_dither);
|
||||||
result[idx] = sample;
|
result[idx] = sample;
|
||||||
if sample > max {
|
if sample > max
|
||||||
|
{
|
||||||
max = sample;
|
max = sample;
|
||||||
}
|
}
|
||||||
if sample < min {
|
if sample < min
|
||||||
|
{
|
||||||
min = sample;
|
min = sample;
|
||||||
}
|
}
|
||||||
data[idx] = biome_data.clone();
|
data[idx] = biome_data.clone();
|
||||||
@@ -212,23 +230,29 @@ fn sample_point(
|
|||||||
size: Vec2,
|
size: Vec2,
|
||||||
border_size: f32,
|
border_size: f32,
|
||||||
border_value: f32,
|
border_value: f32,
|
||||||
) -> f32 {
|
) -> f32
|
||||||
|
{
|
||||||
let x_s = x / cfg.scale;
|
let x_s = x / cfg.scale;
|
||||||
let z_s = z / cfg.scale;
|
let z_s = z / cfg.scale;
|
||||||
|
|
||||||
let mut elevation: f64 = 0.;
|
let mut elevation: f64 = 0.;
|
||||||
for i in 0..cfg.layers.len() {
|
for i in 0..cfg.layers.len()
|
||||||
|
{
|
||||||
let value: f64;
|
let value: f64;
|
||||||
let layer = &cfg.layers[i];
|
let layer = &cfg.layers[i];
|
||||||
if layer.is_rigid {
|
if layer.is_rigid
|
||||||
|
{
|
||||||
value = sample_rigid(x_s, z_s, layer, noise);
|
value = sample_rigid(x_s, z_s, layer, noise);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
value = sample_simple(x_s, z_s, layer, noise);
|
value = sample_simple(x_s, z_s, layer, noise);
|
||||||
}
|
}
|
||||||
elevation += value;
|
elevation += value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if border_size == 0.0 {
|
if border_size == 0.0
|
||||||
|
{
|
||||||
return elevation as f32;
|
return elevation as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,12 +267,14 @@ fn sample_point(
|
|||||||
return border_value.lerp(elevation as f32, d);
|
return border_value.lerp(elevation as f32, d);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sample_simple(x: f64, z: f64, cfg: &GeneratorLayer, noise: &impl NoiseFn<f64, 2>) -> f64 {
|
fn sample_simple(x: f64, z: f64, cfg: &GeneratorLayer, noise: &impl NoiseFn<f64, 2>) -> f64
|
||||||
|
{
|
||||||
let mut freq: f64 = cfg.base_roughness;
|
let mut freq: f64 = cfg.base_roughness;
|
||||||
let mut amp: f64 = 1.;
|
let mut amp: f64 = 1.;
|
||||||
let mut value = 0.;
|
let mut value = 0.;
|
||||||
|
|
||||||
for _ in 0..cfg.layers {
|
for _ in 0..cfg.layers
|
||||||
|
{
|
||||||
let v = noise.get([x * freq, z * freq]);
|
let v = noise.get([x * freq, z * freq]);
|
||||||
value += (v + 1.) * 0.5 * amp;
|
value += (v + 1.) * 0.5 * amp;
|
||||||
freq *= cfg.roughness;
|
freq *= cfg.roughness;
|
||||||
@@ -257,12 +283,14 @@ fn sample_simple(x: f64, z: f64, cfg: &GeneratorLayer, noise: &impl NoiseFn<f64,
|
|||||||
value -= cfg.min_value;
|
value -= cfg.min_value;
|
||||||
return value * cfg.strength;
|
return value * cfg.strength;
|
||||||
}
|
}
|
||||||
fn sample_rigid(x: f64, z: f64, cfg: &GeneratorLayer, noise: &impl NoiseFn<f64, 2>) -> f64 {
|
fn sample_rigid(x: f64, z: f64, cfg: &GeneratorLayer, noise: &impl NoiseFn<f64, 2>) -> f64
|
||||||
|
{
|
||||||
let mut freq: f64 = cfg.base_roughness;
|
let mut freq: f64 = cfg.base_roughness;
|
||||||
let mut amp: f64 = 1.;
|
let mut amp: f64 = 1.;
|
||||||
let mut value = 0.;
|
let mut value = 0.;
|
||||||
let mut weight = 1.;
|
let mut weight = 1.;
|
||||||
for _ in 0..cfg.layers {
|
for _ in 0..cfg.layers
|
||||||
|
{
|
||||||
let mut v = 1. - noise.get([x * freq, z * freq]).abs();
|
let mut v = 1. - noise.get([x * freq, z * freq]).abs();
|
||||||
v *= v;
|
v *= v;
|
||||||
v *= weight;
|
v *= weight;
|
||||||
|
|||||||
@@ -1,312 +0,0 @@
|
|||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
use crate::prelude::Chunk;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
pub const OUTER_RADIUS: f32 = 1.;
|
|
||||||
pub const INNER_RADIUS: f32 = OUTER_RADIUS * (SQRT_3 / 2.);
|
|
||||||
pub const SHORT_DIAGONAL: f32 = 1. * SQRT_3;
|
|
||||||
pub const LONG_DIAGONAL: f32 = 2. * OUTER_RADIUS;
|
|
||||||
const SQRT_3: f32 = 1.7320508076;
|
|
||||||
|
|
||||||
pub fn offset3d_to_world(offset: Vec3) -> Vec3 {
|
|
||||||
let x = (offset.x + (offset.z * 0.5) - (offset.z / 2.).floor()) * (INNER_RADIUS * 2.);
|
|
||||||
return Vec3::new(x, offset.y, offset.z * OUTER_RADIUS * 1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn offset_to_world(offset: IVec2, height: f32) -> Vec3 {
|
|
||||||
let off = offset.as_vec2();
|
|
||||||
let x = (off.x + (off.y * 0.5) - (off.y / 2.).floor()) * (INNER_RADIUS * 2.);
|
|
||||||
return Vec3::new(x, height, off.y * OUTER_RADIUS * 1.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn offset_to_hex(offset: IVec2) -> IVec3 {
|
|
||||||
let mut v = IVec3 {
|
|
||||||
x: offset.x - (offset.y / 2),
|
|
||||||
y: offset.y,
|
|
||||||
z: 0,
|
|
||||||
};
|
|
||||||
v.z = -v.x - v.y;
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn offset_to_index(offset: IVec2, width: usize) -> usize {
|
|
||||||
return offset.x as usize + offset.y as usize * width;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn snap_to_hex_grid(world_pos: Vec3) -> Vec3 {
|
|
||||||
return offset_to_world(world_to_offset_pos(world_pos), world_pos.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn world_to_offset_pos(world_pos: Vec3) -> IVec2 {
|
|
||||||
let offset = world_pos.z / (OUTER_RADIUS * 3.);
|
|
||||||
let x = (world_pos.x / (INNER_RADIUS * 2.)) - offset;
|
|
||||||
let z = -world_pos.x - offset;
|
|
||||||
|
|
||||||
let ix = x.round() as i32;
|
|
||||||
let iz = z.round() as i32;
|
|
||||||
let ox = ix + iz / 2;
|
|
||||||
let oz = iz;
|
|
||||||
return IVec2::new(ox, oz);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn tile_to_world_distance(dist: u32) -> f32 {
|
|
||||||
return dist as f32 * (2. * INNER_RADIUS);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_tile_count_in_range(radius: usize) -> usize {
|
|
||||||
return 1 + 3 * (radius + 1) * radius;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Hash)]
|
|
||||||
pub struct HexCoord {
|
|
||||||
pub hex: IVec3,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for HexCoord {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
f.write_fmt(format_args!("HexCoord{}", self.hex))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HexCoord {
|
|
||||||
pub const DIRECTIONS: [IVec3; 6] = [
|
|
||||||
IVec3::new(0, 1, -1),
|
|
||||||
IVec3::new(1, 0, -1),
|
|
||||||
IVec3::new(1, -1, 0),
|
|
||||||
IVec3::new(0, -1, 1),
|
|
||||||
IVec3::new(-1, 0, 1),
|
|
||||||
IVec3::new(-1, 1, 0),
|
|
||||||
];
|
|
||||||
|
|
||||||
pub const ZERO: HexCoord = HexCoord { hex: IVec3::ZERO };
|
|
||||||
|
|
||||||
pub fn new(x: i32, z: i32) -> Self {
|
|
||||||
return HexCoord {
|
|
||||||
hex: IVec3::new(x, z, -x - z),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_hex(hex: IVec2) -> Self {
|
|
||||||
return HexCoord {
|
|
||||||
hex: IVec3::new(hex.x, hex.y, -hex.x - hex.y),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
pub fn from_grid_pos(x: usize, z: usize) -> Self {
|
|
||||||
return HexCoord::new(x as i32 - (z as i32 / 2), z as i32);
|
|
||||||
}
|
|
||||||
pub fn from_offset(offset_pos: IVec2) -> Self {
|
|
||||||
return HexCoord {
|
|
||||||
hex: offset_to_hex(offset_pos),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_world_pos(world_pos: Vec3) -> Self {
|
|
||||||
let offset = world_pos.z / (OUTER_RADIUS * 3.);
|
|
||||||
let mut x = world_pos.x / (INNER_RADIUS * 2.);
|
|
||||||
let mut z = -x;
|
|
||||||
z -= offset;
|
|
||||||
x -= offset;
|
|
||||||
|
|
||||||
let i_x = x.round() as i32;
|
|
||||||
let i_z = (-x - z).round() as i32;
|
|
||||||
let offset_pos = IVec2::new(i_x + i_z / 2, i_z);
|
|
||||||
|
|
||||||
return Self::from_offset(offset_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, map_height: usize, map_width: usize) -> bool {
|
|
||||||
let off = self.to_offset();
|
|
||||||
if off.x < 0 || off.y < 0 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if off.x >= map_width as i32 || off.y >= map_height as i32 {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn is_on_chunk_edge(&self) -> bool {
|
|
||||||
let offset = self.to_offset().rem_euclid(IVec2::splat(Chunk::SIZE as i32));
|
|
||||||
let e = (Chunk::SIZE - 1) as i32;
|
|
||||||
return offset.x == 0 || offset.y == 0 || offset.x == e || offset.y == e;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_chunk_pos(&self) -> IVec2 {
|
|
||||||
let off = self.to_offset();
|
|
||||||
|
|
||||||
return IVec2 {
|
|
||||||
x: (off.x as f32 / Chunk::SIZE as f32).floor() as i32,
|
|
||||||
y: (off.y as f32 / Chunk::SIZE as f32).floor() as i32,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Converts this coordinate to it's chunk local equivalent
|
|
||||||
pub fn to_chunk(&self) -> HexCoord {
|
|
||||||
let c_pos = self.to_chunk_pos();
|
|
||||||
let off = self.to_offset();
|
|
||||||
return HexCoord::from_offset(
|
|
||||||
(
|
|
||||||
off.x - (c_pos.x * Chunk::SIZE as i32),
|
|
||||||
off.y - (c_pos.y * Chunk::SIZE as i32),
|
|
||||||
)
|
|
||||||
.into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_world(&self, height: f32) -> Vec3 {
|
|
||||||
return offset_to_world(self.to_offset(), height);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_offset(&self) -> IVec2 {
|
|
||||||
return IVec2::new(self.hex.x + (self.hex.y / 2), self.hex.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert the current coordiante to an index
|
|
||||||
pub fn to_index(&self, width: usize) -> usize {
|
|
||||||
return ((self.hex.x + self.hex.y * width as i32) + (self.hex.y / 2)) as usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the index of this coord in the chunk array.
|
|
||||||
///
|
|
||||||
/// [`width`] is in number of chunks
|
|
||||||
pub fn to_chunk_index(&self, width: usize) -> usize {
|
|
||||||
let pos = self.to_chunk_pos();
|
|
||||||
return (pos.x + pos.y * width as i32) as usize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Gets the index of this tile in the chunk
|
|
||||||
pub fn to_chunk_local_index(&self) -> usize {
|
|
||||||
return self.to_chunk().to_index(Chunk::SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn distance(&self, other: &HexCoord) -> i32 {
|
|
||||||
return (self.hex.x - other.hex.x).abs() + (self.hex.y - other.hex.y).abs() + (self.hex.z - other.hex.z).abs();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn rotate_around(&self, center: &HexCoord, angle: i32) -> HexCoord {
|
|
||||||
if self == center || angle == 0 {
|
|
||||||
return self.clone();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut a = angle % 6;
|
|
||||||
let mut pc = self.hex - center.hex;
|
|
||||||
|
|
||||||
if a > 0 {
|
|
||||||
for _ in 0..a {
|
|
||||||
pc = Self::slide_right(pc);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
a = a.abs();
|
|
||||||
for _ in 0..a {
|
|
||||||
pc = Self::slide_left(pc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return HexCoord::from_hex(pc.xy() + center.hex.xy());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn slide_left(hex: IVec3) -> IVec3 {
|
|
||||||
return (hex * -1).yzx();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn slide_right(hex: IVec3) -> IVec3 {
|
|
||||||
return (hex * -1).zxy();
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn scale(&self, dir: i32, radius: usize) -> HexCoord {
|
|
||||||
let s = Self::DIRECTIONS[(dir % 6) as usize] * radius as i32;
|
|
||||||
return Self::from_hex(self.hex.xy() + s.xy());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neighbor(&self, dir: usize) -> HexCoord {
|
|
||||||
let d = Self::DIRECTIONS[dir % 6];
|
|
||||||
return Self::from_hex(self.hex.xy() + d.xy());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neighbors(&self) -> [HexCoord; 6] {
|
|
||||||
return [
|
|
||||||
self.get_neighbor(0),
|
|
||||||
self.get_neighbor(1),
|
|
||||||
self.get_neighbor(2),
|
|
||||||
self.get_neighbor(3),
|
|
||||||
self.get_neighbor(4),
|
|
||||||
self.get_neighbor(5),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hex_select(&self, radius: usize, include_center: bool) -> Vec<HexCoord> {
|
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
|
||||||
let mut result = Vec::with_capacity(get_tile_count_in_range(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 hex_select_bounded(
|
|
||||||
&self,
|
|
||||||
radius: usize,
|
|
||||||
include_center: bool,
|
|
||||||
height: usize,
|
|
||||||
width: usize,
|
|
||||||
) -> Vec<HexCoord> {
|
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
|
||||||
let mut result = Vec::with_capacity(get_tile_count_in_range(radius));
|
|
||||||
|
|
||||||
if include_center {
|
|
||||||
if self.is_in_bounds(height, width) {
|
|
||||||
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);
|
|
||||||
if p.is_in_bounds(height, width) {
|
|
||||||
result.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn select_ring(&self, radius: usize) -> Vec<HexCoord> {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +1,10 @@
|
|||||||
|
pub mod biome_asset;
|
||||||
pub mod biome_painter;
|
pub mod biome_painter;
|
||||||
pub mod consts;
|
pub mod consts;
|
||||||
pub mod generators;
|
pub mod generators;
|
||||||
pub mod heightmap;
|
pub mod heightmap;
|
||||||
pub mod hex_utils;
|
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod states;
|
pub mod states;
|
||||||
pub mod tile_manager;
|
pub mod tile_manager;
|
||||||
pub mod tile_mapper;
|
pub mod tile_mapper;
|
||||||
pub mod biome_asset;
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ use bevy::{
|
|||||||
use noise::NoiseFn;
|
use noise::NoiseFn;
|
||||||
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelIterator, ParallelIterator};
|
||||||
|
|
||||||
use super::chunk::Chunk;
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Clone, Resource)]
|
#[derive(Clone, Resource)]
|
||||||
pub struct BiomeMap {
|
pub struct BiomeMap
|
||||||
|
{
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
pub size: UVec2,
|
pub size: UVec2,
|
||||||
@@ -17,26 +18,33 @@ pub struct BiomeMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Default, Clone, Copy)]
|
||||||
pub struct BiomeData {
|
pub struct BiomeData
|
||||||
|
{
|
||||||
pub moisture: f32,
|
pub moisture: f32,
|
||||||
pub temperature: f32,
|
pub temperature: f32,
|
||||||
pub continentality: f32,
|
pub continentality: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Vec3> for &BiomeData {
|
impl Into<Vec3> for &BiomeData
|
||||||
fn into(self) -> Vec3 {
|
{
|
||||||
|
fn into(self) -> Vec3
|
||||||
|
{
|
||||||
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<Vec3> for BiomeData {
|
impl Into<Vec3> for BiomeData
|
||||||
fn into(self) -> Vec3 {
|
{
|
||||||
|
fn into(self) -> Vec3
|
||||||
|
{
|
||||||
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
return Vec3::new(self.moisture, self.temperature, self.continentality);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BiomeMap {
|
impl BiomeMap
|
||||||
pub fn new(size: UVec2, biome_count: usize) -> Self {
|
{
|
||||||
|
pub fn new(size: UVec2, biome_count: usize) -> Self
|
||||||
|
{
|
||||||
let len = size.x as usize * size.y as usize * Chunk::AREA;
|
let len = size.x as usize * size.y as usize * Chunk::AREA;
|
||||||
return BiomeMap {
|
return BiomeMap {
|
||||||
size,
|
size,
|
||||||
@@ -47,14 +55,17 @@ impl BiomeMap {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn blend(&mut self, count: usize) {
|
pub fn blend(&mut self, count: usize)
|
||||||
|
{
|
||||||
assert!(count != 0, "Count cannot be 0");
|
assert!(count != 0, "Count cannot be 0");
|
||||||
for _ in 0..count {
|
for _ in 0..count
|
||||||
|
{
|
||||||
self.blend_once();
|
self.blend_once();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blend_once(&mut self) {
|
fn blend_once(&mut self)
|
||||||
|
{
|
||||||
let c: Vec<BiomeChunk> = (0..self.chunks.len())
|
let c: Vec<BiomeChunk> = (0..self.chunks.len())
|
||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|i| &self.chunks[i])
|
.map(|i| &self.chunks[i])
|
||||||
@@ -63,7 +74,8 @@ impl BiomeMap {
|
|||||||
.into_par_iter()
|
.into_par_iter()
|
||||||
.map(|y| {
|
.map(|y| {
|
||||||
let mut new_tiles = Vec::with_capacity(self.width);
|
let mut new_tiles = Vec::with_capacity(self.width);
|
||||||
for x in 0..Chunk::SIZE {
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let tx = x as u32 + chunk.offset.x * Chunk::SIZE as u32;
|
let tx = x as u32 + chunk.offset.x * Chunk::SIZE as u32;
|
||||||
let ty = y as u32 + chunk.offset.y * Chunk::SIZE as u32;
|
let ty = y as u32 + chunk.offset.y * Chunk::SIZE as u32;
|
||||||
let kernel = self.get_kernel(tx as i32, ty as i32);
|
let kernel = self.get_kernel(tx as i32, ty as i32);
|
||||||
@@ -76,7 +88,8 @@ impl BiomeMap {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let sum: f32 = r.iter().sum();
|
let sum: f32 = r.iter().sum();
|
||||||
if sum == 0. {
|
if sum == 0.
|
||||||
|
{
|
||||||
new_tiles.push(vec![0.; self.biome_count]);
|
new_tiles.push(vec![0.; self.biome_count]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -96,7 +109,8 @@ impl BiomeMap {
|
|||||||
self.chunks = c;
|
self.chunks = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
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 [
|
return [
|
||||||
self.get_biome(x - 1, y - 1),
|
self.get_biome(x - 1, y - 1),
|
||||||
self.get_biome(x, y - 1),
|
self.get_biome(x, y - 1),
|
||||||
@@ -110,11 +124,14 @@ impl BiomeMap {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome(&self, x: i32, y: i32) -> Option<&Vec<f32>> {
|
pub fn get_biome(&self, x: i32, y: i32) -> Option<&Vec<f32>>
|
||||||
if x < 0 || y < 0 {
|
{
|
||||||
|
if x < 0 || y < 0
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
if x >= self.width as i32 || y >= self.height as i32 {
|
if x >= self.width as i32 || y >= self.height as i32
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +142,8 @@ impl BiomeMap {
|
|||||||
return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE));
|
return Some(chunk.get_biome(x as usize - cx * Chunk::SIZE, y as usize - cy * Chunk::SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_id(&self, x: usize, y: usize) -> usize {
|
pub fn get_biome_id(&self, x: usize, y: usize) -> usize
|
||||||
|
{
|
||||||
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
|
|
||||||
@@ -134,7 +152,8 @@ impl BiomeMap {
|
|||||||
return chunk.get_biome_id(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE));
|
return chunk.get_biome_id(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_id_dithered(&self, x: usize, y: usize, noise: &impl NoiseFn<f64, 2>, scale: f64) -> usize {
|
pub fn get_biome_id_dithered(&self, x: usize, y: usize, noise: &impl NoiseFn<f64, 2>, scale: f64) -> usize
|
||||||
|
{
|
||||||
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
|
|
||||||
@@ -143,7 +162,8 @@ impl BiomeMap {
|
|||||||
return chunk.get_biome_id_dithered(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE), noise, scale);
|
return chunk.get_biome_id_dithered(x - (cx * Chunk::SIZE), y - (cy * Chunk::SIZE), noise, scale);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData {
|
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData
|
||||||
|
{
|
||||||
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cx = (x as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
let cy = (y as f32 / Chunk::SIZE as f32).floor() as usize;
|
||||||
|
|
||||||
@@ -154,28 +174,35 @@ impl BiomeMap {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct BiomeChunk {
|
pub struct BiomeChunk
|
||||||
|
{
|
||||||
pub tiles: Vec<Vec<f32>>,
|
pub tiles: Vec<Vec<f32>>,
|
||||||
pub offset: UVec2,
|
pub offset: UVec2,
|
||||||
pub data: [BiomeData; Chunk::AREA],
|
pub data: [BiomeData; Chunk::AREA],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BiomeChunk {
|
impl BiomeChunk
|
||||||
pub fn get_biome(&self, x: usize, y: usize) -> &Vec<f32> {
|
{
|
||||||
|
pub fn get_biome(&self, x: usize, y: usize) -> &Vec<f32>
|
||||||
|
{
|
||||||
return &self.tiles[x + y * Chunk::SIZE];
|
return &self.tiles[x + y * Chunk::SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData {
|
pub fn get_biome_data(&self, x: usize, y: usize) -> &BiomeData
|
||||||
|
{
|
||||||
return &self.data[x + y * Chunk::SIZE];
|
return &self.data[x + y * Chunk::SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_id(&self, x: usize, y: usize) -> usize {
|
pub fn get_biome_id(&self, x: usize, y: usize) -> usize
|
||||||
|
{
|
||||||
let b = self.get_biome(x, y);
|
let b = self.get_biome(x, y);
|
||||||
let mut max = 0.;
|
let mut max = 0.;
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
for i in 0..b.len() {
|
for i in 0..b.len()
|
||||||
|
{
|
||||||
let blend = b[i];
|
let blend = b[i];
|
||||||
if blend > max {
|
if blend > max
|
||||||
|
{
|
||||||
max = blend;
|
max = blend;
|
||||||
idx = i;
|
idx = i;
|
||||||
}
|
}
|
||||||
@@ -183,17 +210,21 @@ impl BiomeChunk {
|
|||||||
return idx;
|
return idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_id_dithered(&self, x: usize, y: usize, noise: &impl NoiseFn<f64, 2>, scale: f64) -> usize {
|
pub fn get_biome_id_dithered(&self, x: usize, y: usize, noise: &impl NoiseFn<f64, 2>, scale: f64) -> usize
|
||||||
|
{
|
||||||
let mut cur_id = self.get_biome_id(x, y);
|
let mut cur_id = self.get_biome_id(x, y);
|
||||||
let b = self.get_biome(x, y);
|
let b = self.get_biome(x, y);
|
||||||
let n = (noise.get([x as f64 / scale, y as f64 / scale]) as f32 - 0.5)/ 2.0;
|
let n = (noise.get([x as f64 / scale, y as f64 / scale]) as f32 - 0.5) / 2.0;
|
||||||
let mut max = b[cur_id] + n;
|
let mut max = b[cur_id] + n;
|
||||||
for i in 0..b.len() {
|
for i in 0..b.len()
|
||||||
|
{
|
||||||
let blend = b[i];
|
let blend = b[i];
|
||||||
if blend == 0. {
|
if blend == 0.
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if blend > max {
|
if blend > max
|
||||||
|
{
|
||||||
max = blend + n;
|
max = blend + n;
|
||||||
cur_id = i;
|
cur_id = i;
|
||||||
}
|
}
|
||||||
@@ -204,18 +235,22 @@ impl BiomeChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests
|
||||||
|
{
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn biome_blend() {
|
fn biome_blend()
|
||||||
|
{
|
||||||
let mut biome = BiomeMap::new(UVec2::splat(4), 8);
|
let mut biome = BiomeMap::new(UVec2::splat(4), 8);
|
||||||
let w = biome.size.x as usize;
|
let w = biome.size.x as usize;
|
||||||
let h = biome.size.y as usize;
|
let h = biome.size.y as usize;
|
||||||
|
|
||||||
for y in 0..h {
|
for y in 0..h
|
||||||
for x in 0..w {
|
{
|
||||||
|
for x in 0..w
|
||||||
|
{
|
||||||
let mut b = vec![0.; biome.biome_count];
|
let mut b = vec![0.; biome.biome_count];
|
||||||
let idx = (x + y) % biome.biome_count;
|
let idx = (x + y) % biome.biome_count;
|
||||||
b[idx] = 1.;
|
b[idx] = 1.;
|
||||||
@@ -227,7 +262,8 @@ mod tests {
|
|||||||
assert!(biome.chunks.iter().all(|f| f.tiles.len() == Chunk::AREA), "Data Lost");
|
assert!(biome.chunks.iter().all(|f| f.tiles.len() == Chunk::AREA), "Data Lost");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn generate_chunk(x: usize, y: usize, biome: Vec<f32>) -> BiomeChunk {
|
fn generate_chunk(x: usize, y: usize, biome: Vec<f32>) -> BiomeChunk
|
||||||
|
{
|
||||||
let chunk = BiomeChunk {
|
let chunk = BiomeChunk {
|
||||||
offset: UVec2::new(x as u32, y as u32),
|
offset: UVec2::new(x as u32, y as u32),
|
||||||
data: [BiomeData::default(); Chunk::AREA],
|
data: [BiomeData::default(); Chunk::AREA],
|
||||||
|
|||||||
@@ -1,79 +0,0 @@
|
|||||||
use crate::hex_utils::SHORT_DIAGONAL;
|
|
||||||
use bevy::prelude::*;
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Chunk {
|
|
||||||
pub heights: [f32; Chunk::AREA],
|
|
||||||
pub textures: [[u32; 2]; Chunk::AREA],
|
|
||||||
// pub biome_data: [BiomeData; Chunk::AREA],
|
|
||||||
pub biome_id: [usize; Chunk::AREA],
|
|
||||||
pub chunk_offset: IVec2,
|
|
||||||
pub min_level: f32,
|
|
||||||
pub max_level: f32,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for Chunk {
|
|
||||||
fn default() -> Self {
|
|
||||||
Self {
|
|
||||||
heights: [0.; Chunk::AREA],
|
|
||||||
textures: [[0; 2]; Chunk::AREA],
|
|
||||||
// biome_data: [BiomeData::default(); Chunk::AREA],
|
|
||||||
biome_id: [0; Chunk::AREA],
|
|
||||||
chunk_offset: Default::default(),
|
|
||||||
min_level: 0.0,
|
|
||||||
max_level: 0.0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Chunk {
|
|
||||||
pub const SIZE: usize = 64;
|
|
||||||
pub const AREA: usize = Chunk::SIZE * Chunk::SIZE;
|
|
||||||
pub const WORLD_WIDTH: f32 = Chunk::SIZE as f32 * SHORT_DIAGONAL;
|
|
||||||
pub const WORLD_HEIGHT: f32 = Chunk::SIZE as f32 * 1.5;
|
|
||||||
pub const WORLD_SIZE: Vec2 = Vec2::new(Chunk::WORLD_WIDTH, Chunk::WORLD_HEIGHT);
|
|
||||||
|
|
||||||
pub fn get_pos_z_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for x in 0..Chunk::SIZE {
|
|
||||||
let idx = x + (Chunk::SIZE - 1) * Chunk::SIZE;
|
|
||||||
data[x] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neg_z_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for x in 0..Chunk::SIZE {
|
|
||||||
data[x] = self.heights[x];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_pos_x_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
|
||||||
let idx = (Chunk::SIZE - 1) + z * Chunk::SIZE;
|
|
||||||
data[z] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_neg_x_edge(&self) -> [f32; Chunk::SIZE] {
|
|
||||||
let mut data = [0.; Chunk::SIZE];
|
|
||||||
|
|
||||||
for z in 0..Chunk::SIZE {
|
|
||||||
let idx = z * Chunk::SIZE;
|
|
||||||
data[z] = self.heights[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -2,11 +2,12 @@ use bevy::prelude::*;
|
|||||||
use bevy_inspector_egui::InspectorOptions;
|
use bevy_inspector_egui::InspectorOptions;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::chunk::Chunk;
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Resource, Reflect, Default, Clone)]
|
#[derive(Resource, Reflect, Default, Clone)]
|
||||||
#[reflect(Resource)]
|
#[reflect(Resource)]
|
||||||
pub struct GenerationConfig {
|
pub struct GenerationConfig
|
||||||
|
{
|
||||||
pub sea_level: f64,
|
pub sea_level: f64,
|
||||||
pub border_size: f32,
|
pub border_size: f32,
|
||||||
pub biome_blend: usize,
|
pub biome_blend: usize,
|
||||||
@@ -17,23 +18,28 @@ pub struct GenerationConfig {
|
|||||||
pub size: UVec2,
|
pub size: UVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GenerationConfig {
|
impl GenerationConfig
|
||||||
pub fn get_total_width(&self) -> usize {
|
{
|
||||||
|
pub fn get_total_width(&self) -> usize
|
||||||
|
{
|
||||||
return self.size.x as usize * Chunk::SIZE;
|
return self.size.x as usize * Chunk::SIZE;
|
||||||
}
|
}
|
||||||
pub fn get_total_height(&self) -> usize {
|
pub fn get_total_height(&self) -> usize
|
||||||
|
{
|
||||||
return self.size.y as usize * Chunk::SIZE;
|
return self.size.y as usize * Chunk::SIZE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Default, Reflect, Clone, Debug)]
|
#[derive(Serialize, Deserialize, Default, Reflect, Clone, Debug)]
|
||||||
pub struct NoiseConfig {
|
pub struct NoiseConfig
|
||||||
|
{
|
||||||
pub scale: f64,
|
pub scale: f64,
|
||||||
pub layers: Vec<GeneratorLayer>,
|
pub layers: Vec<GeneratorLayer>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Reflect, InspectorOptions, Serialize, Deserialize, Debug, Clone, Default)]
|
#[derive(Reflect, InspectorOptions, Serialize, Deserialize, Debug, Clone, Default)]
|
||||||
pub struct GeneratorLayer {
|
pub struct GeneratorLayer
|
||||||
|
{
|
||||||
pub strength: f64,
|
pub strength: f64,
|
||||||
pub min_value: f64,
|
pub min_value: f64,
|
||||||
pub base_roughness: f64,
|
pub base_roughness: f64,
|
||||||
|
|||||||
@@ -1,14 +1,11 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use hex::prelude::*;
|
||||||
|
|
||||||
use crate::hex_utils::*;
|
use super::mesh_chunk::MeshChunkData;
|
||||||
|
|
||||||
use super::{
|
|
||||||
chunk::Chunk,
|
|
||||||
mesh_chunk::MeshChunkData,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Resource, Clone)]
|
#[derive(Resource, Clone)]
|
||||||
pub struct Map {
|
pub struct Map
|
||||||
|
{
|
||||||
pub chunks: Vec<Chunk>,
|
pub chunks: Vec<Chunk>,
|
||||||
pub height: usize,
|
pub height: usize,
|
||||||
pub width: usize,
|
pub width: usize,
|
||||||
@@ -18,20 +15,25 @@ pub struct Map {
|
|||||||
pub biome_count: usize,
|
pub biome_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Map {
|
impl Map
|
||||||
pub fn get_tile_count(&self) -> usize {
|
{
|
||||||
|
pub fn get_tile_count(&self) -> usize
|
||||||
|
{
|
||||||
return self.get_tile_width() * self.get_tile_height();
|
return self.get_tile_width() * self.get_tile_height();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tile_width(&self) -> usize {
|
pub fn get_tile_width(&self) -> usize
|
||||||
|
{
|
||||||
return self.width * Chunk::SIZE;
|
return self.width * Chunk::SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_tile_height(&self) -> usize {
|
pub fn get_tile_height(&self) -> usize
|
||||||
|
{
|
||||||
return self.height * Chunk::SIZE;
|
return self.height * Chunk::SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_chunk_mesh_data(&self, chunk_index: usize) -> MeshChunkData {
|
pub fn get_chunk_mesh_data(&self, chunk_index: usize) -> MeshChunkData
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _spawn_span = info_span!("Chunk Mesh Data").entered();
|
let _spawn_span = info_span!("Chunk Mesh Data").entered();
|
||||||
let chunk = &self.chunks[chunk_index];
|
let chunk = &self.chunks[chunk_index];
|
||||||
@@ -45,36 +47,45 @@ impl Map {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_distance_from_land(&self, chunk_offset: IVec2, range: usize) -> [f32; Chunk::AREA] {
|
fn get_distance_from_land(&self, chunk_offset: IVec2, range: usize) -> [f32; Chunk::AREA]
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _spawn_span = info_span!("Chunk Land Dist Data").entered();
|
let _spawn_span = info_span!("Chunk Land Dist Data").entered();
|
||||||
let mut dists = [0.0; Chunk::AREA];
|
let mut dists = [0.0; Chunk::AREA];
|
||||||
let cx = chunk_offset.x as usize * Chunk::SIZE;
|
let cx = chunk_offset.x as usize * Chunk::SIZE;
|
||||||
let cz = chunk_offset.y as usize * Chunk::SIZE;
|
let cz = chunk_offset.y as usize * Chunk::SIZE;
|
||||||
for z in 0..Chunk::SIZE {
|
for z in 0..Chunk::SIZE
|
||||||
for x in 0..Chunk::SIZE {
|
{
|
||||||
|
for x in 0..Chunk::SIZE
|
||||||
|
{
|
||||||
let coord = HexCoord::from_grid_pos(x + cx, z + cz);
|
let coord = HexCoord::from_grid_pos(x + cx, z + cz);
|
||||||
let index = coord.to_chunk_local_index();
|
let index = coord.to_chunk_local_index();
|
||||||
|
|
||||||
if !self.is_in_bounds(&coord) {
|
if !self.is_in_bounds(&coord)
|
||||||
|
{
|
||||||
warn!("Coord is not in bounds!?");
|
warn!("Coord is not in bounds!?");
|
||||||
}
|
}
|
||||||
|
|
||||||
//Current tile is land tile
|
//Current tile is land tile
|
||||||
if self.sample_height(&coord) > self.sealevel {
|
if self.sample_height(&coord) > self.sealevel
|
||||||
|
{
|
||||||
dists[index] = 0.0;
|
dists[index] = 0.0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Find closest land tile
|
//Find closest land tile
|
||||||
if let Some(d) = self.hex_select_first(&coord, range, false, |_t, h, r| {
|
if let Some(d) = self.hex_select_first(&coord, range, false, |_t, h, r| {
|
||||||
if h > self.sealevel {
|
if h > self.sealevel
|
||||||
|
{
|
||||||
return Some(r as f32);
|
return Some(r as f32);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
dists[index] = d;
|
dists[index] = d;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
dists[index] = range as f32;
|
dists[index] = range as f32;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -82,14 +93,17 @@ impl Map {
|
|||||||
return dists;
|
return dists;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_neighbors(&self, pos: &HexCoord) -> [Option<f32>; 6] {
|
pub fn get_neighbors(&self, pos: &HexCoord) -> [Option<f32>; 6]
|
||||||
|
{
|
||||||
let mut results: [Option<f32>; 6] = [None; 6];
|
let mut results: [Option<f32>; 6] = [None; 6];
|
||||||
let w = self.width * Chunk::SIZE;
|
let w = self.width * Chunk::SIZE;
|
||||||
let h = self.height * Chunk::SIZE;
|
let h = self.height * Chunk::SIZE;
|
||||||
let n_tiles = pos.get_neighbors();
|
let n_tiles = pos.get_neighbors();
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
let n_tile = n_tiles[i];
|
let n_tile = n_tiles[i];
|
||||||
if !n_tile.is_in_bounds(h, w) {
|
if !n_tile.is_in_bounds(h, w)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let c_idx = n_tile.to_chunk_index(self.width);
|
let c_idx = n_tile.to_chunk_index(self.width);
|
||||||
@@ -100,7 +114,8 @@ impl Map {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_height(&self, pos: &HexCoord) -> f32 {
|
pub fn sample_height(&self, pos: &HexCoord) -> f32
|
||||||
|
{
|
||||||
assert!(
|
assert!(
|
||||||
self.is_in_bounds(pos),
|
self.is_in_bounds(pos),
|
||||||
"The provided coordinate is not within the map bounds"
|
"The provided coordinate is not within the map bounds"
|
||||||
@@ -110,7 +125,8 @@ impl Map {
|
|||||||
return chunk.heights[pos.to_chunk_local_index()];
|
return chunk.heights[pos.to_chunk_local_index()];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32 {
|
pub fn sample_height_mut(&mut self, pos: &HexCoord) -> &mut f32
|
||||||
|
{
|
||||||
assert!(
|
assert!(
|
||||||
self.is_in_bounds(pos),
|
self.is_in_bounds(pos),
|
||||||
"The provided coordinate is not within the map bounds"
|
"The provided coordinate is not within the map bounds"
|
||||||
@@ -120,11 +136,13 @@ impl Map {
|
|||||||
return &mut chunk.heights[pos.to_chunk_local_index()];
|
return &mut chunk.heights[pos.to_chunk_local_index()];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
|
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool
|
||||||
|
{
|
||||||
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
|
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_biome_id(&self, pos: &HexCoord) -> usize {
|
pub fn get_biome_id(&self, pos: &HexCoord) -> usize
|
||||||
|
{
|
||||||
assert!(
|
assert!(
|
||||||
self.is_in_bounds(pos),
|
self.is_in_bounds(pos),
|
||||||
"The provided coordinate is not within the map bounds"
|
"The provided coordinate is not within the map bounds"
|
||||||
@@ -134,13 +152,15 @@ impl Map {
|
|||||||
return chunk.biome_id[pos.to_chunk_local_index()];
|
return chunk.biome_id[pos.to_chunk_local_index()];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_center(&self) -> Vec3 {
|
pub fn get_center(&self) -> Vec3
|
||||||
|
{
|
||||||
let w = self.get_world_width();
|
let w = self.get_world_width();
|
||||||
let h = self.get_world_height();
|
let h = self.get_world_height();
|
||||||
return Vec3::new(w / 2., self.sealevel, h / 2.);
|
return Vec3::new(w / 2., self.sealevel, h / 2.);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_center_with_height(&self) -> Vec3 {
|
pub fn get_center_with_height(&self) -> Vec3
|
||||||
|
{
|
||||||
let w = self.get_world_width();
|
let w = self.get_world_width();
|
||||||
let h = self.get_world_height();
|
let h = self.get_world_height();
|
||||||
let mut pos = Vec3::new(w / 2., self.sealevel, h / 2.);
|
let mut pos = Vec3::new(w / 2., self.sealevel, h / 2.);
|
||||||
@@ -148,22 +168,27 @@ impl Map {
|
|||||||
return pos;
|
return pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_world_width(&self) -> f32 {
|
pub fn get_world_width(&self) -> f32
|
||||||
|
{
|
||||||
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
||||||
}
|
}
|
||||||
pub fn get_world_height(&self) -> f32 {
|
pub fn get_world_height(&self) -> f32
|
||||||
|
{
|
||||||
return (self.height * Chunk::SIZE) as f32 * 1.5;
|
return (self.height * Chunk::SIZE) as f32 * 1.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_world_size(&self) -> Vec2 {
|
pub fn get_world_size(&self) -> Vec2
|
||||||
|
{
|
||||||
return Vec2::new(self.get_world_width(), self.get_world_height());
|
return Vec2::new(self.get_world_width(), self.get_world_height());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_height(&mut self, pos: &HexCoord, height: f32) {
|
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;
|
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<(HexCoord, f32)> {
|
pub fn create_crater(&mut self, pos: &HexCoord, radius: usize, depth: f32) -> Vec<(HexCoord, f32)>
|
||||||
|
{
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
let tiles = self.hex_select_mut(pos, radius, true, |p, h, r| {
|
let tiles = self.hex_select_mut(pos, radius, true, |p, h, r| {
|
||||||
@@ -184,22 +209,30 @@ impl Map {
|
|||||||
{
|
{
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
let mut result = if include_center {
|
let mut result = if include_center
|
||||||
|
{
|
||||||
Vec::with_capacity(get_tile_count_in_range(radius) + 1)
|
Vec::with_capacity(get_tile_count_in_range(radius) + 1)
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Vec::with_capacity(get_tile_count_in_range(radius))
|
Vec::with_capacity(get_tile_count_in_range(radius))
|
||||||
};
|
};
|
||||||
if include_center {
|
if include_center
|
||||||
|
{
|
||||||
let h = self.sample_height(¢er);
|
let h = self.sample_height(¢er);
|
||||||
result.push((op)(center, h, 0));
|
result.push((op)(center, h, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
for k in 0..(radius + 1) {
|
for k in 0..(radius + 1)
|
||||||
|
{
|
||||||
let mut p = center.scale(4, k);
|
let mut p = center.scale(4, k);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
for _j in 0..k {
|
{
|
||||||
|
for _j in 0..k
|
||||||
|
{
|
||||||
p = p.get_neighbor(i);
|
p = p.get_neighbor(i);
|
||||||
if self.is_in_bounds(&p) {
|
if self.is_in_bounds(&p)
|
||||||
|
{
|
||||||
let h = self.sample_height(&p);
|
let h = self.sample_height(&p);
|
||||||
result.push((op)(&p, h, k));
|
result.push((op)(&p, h, k));
|
||||||
}
|
}
|
||||||
@@ -222,23 +255,30 @@ impl Map {
|
|||||||
{
|
{
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
if include_center {
|
if include_center
|
||||||
|
{
|
||||||
let h = self.sample_height(¢er);
|
let h = self.sample_height(¢er);
|
||||||
let r = (op)(center, h, 0);
|
let r = (op)(center, h, 0);
|
||||||
if r.is_some() {
|
if r.is_some()
|
||||||
|
{
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for k in 0..(radius + 1) {
|
for k in 0..(radius + 1)
|
||||||
|
{
|
||||||
let mut p = center.scale(4, k);
|
let mut p = center.scale(4, k);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
for _j in 0..k {
|
{
|
||||||
|
for _j in 0..k
|
||||||
|
{
|
||||||
p = p.get_neighbor(i);
|
p = p.get_neighbor(i);
|
||||||
if self.is_in_bounds(&p) {
|
if self.is_in_bounds(&p)
|
||||||
|
{
|
||||||
let h = self.sample_height(&p);
|
let h = self.sample_height(&p);
|
||||||
let r = (op)(&p, h, k);
|
let r = (op)(&p, h, k);
|
||||||
if r.is_some() {
|
if r.is_some()
|
||||||
|
{
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -265,15 +305,20 @@ impl Map {
|
|||||||
"Start radius cannot be lower than end radius"
|
"Start radius cannot be lower than end radius"
|
||||||
);
|
);
|
||||||
|
|
||||||
for k in start_radius..(end_radius + 1) {
|
for k in start_radius..(end_radius + 1)
|
||||||
|
{
|
||||||
let mut p = center.scale(4, k);
|
let mut p = center.scale(4, k);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
for _j in 0..k {
|
{
|
||||||
|
for _j in 0..k
|
||||||
|
{
|
||||||
p = p.get_neighbor(i);
|
p = p.get_neighbor(i);
|
||||||
if self.is_in_bounds(&p) {
|
if self.is_in_bounds(&p)
|
||||||
|
{
|
||||||
let h = self.sample_height(&p);
|
let h = self.sample_height(&p);
|
||||||
let r = (op)(&p, h, k);
|
let r = (op)(&p, h, k);
|
||||||
if r.is_some() {
|
if r.is_some()
|
||||||
|
{
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,22 +341,30 @@ impl Map {
|
|||||||
{
|
{
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
let mut result = if include_center {
|
let mut result = if include_center
|
||||||
|
{
|
||||||
Vec::with_capacity(get_tile_count_in_range(radius) + 1)
|
Vec::with_capacity(get_tile_count_in_range(radius) + 1)
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
Vec::with_capacity(get_tile_count_in_range(radius))
|
Vec::with_capacity(get_tile_count_in_range(radius))
|
||||||
};
|
};
|
||||||
if include_center {
|
if include_center
|
||||||
|
{
|
||||||
let h = self.sample_height_mut(¢er);
|
let h = self.sample_height_mut(¢er);
|
||||||
result.push((op)(center, h, 0));
|
result.push((op)(center, h, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
for k in 0..(radius + 1) {
|
for k in 0..(radius + 1)
|
||||||
|
{
|
||||||
let mut p = center.scale(4, k);
|
let mut p = center.scale(4, k);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
for _j in 0..k {
|
{
|
||||||
|
for _j in 0..k
|
||||||
|
{
|
||||||
p = p.get_neighbor(i);
|
p = p.get_neighbor(i);
|
||||||
if self.is_in_bounds(&p) {
|
if self.is_in_bounds(&p)
|
||||||
|
{
|
||||||
let h = self.sample_height_mut(&p);
|
let h = self.sample_height_mut(&p);
|
||||||
result.push((op)(&p, h, k));
|
result.push((op)(&p, h, k));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use bevy::{math::VectorSpace, prelude::*};
|
|||||||
use image::ImageBuffer;
|
use image::ImageBuffer;
|
||||||
use rayon::prelude::*;
|
use rayon::prelude::*;
|
||||||
|
|
||||||
use crate::hex_utils::HexCoord;
|
use hex::prelude::*;
|
||||||
|
|
||||||
use super::{biome_map::BiomeMap, chunk::Chunk, map::Map};
|
use super::{biome_map::BiomeMap, map::Map};
|
||||||
|
|
||||||
pub fn render_image(
|
pub fn render_image(
|
||||||
size: UVec2,
|
size: UVec2,
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ use std::collections::VecDeque;
|
|||||||
|
|
||||||
use bevy::math::IVec2;
|
use bevy::math::IVec2;
|
||||||
|
|
||||||
use crate::hex_utils::HexCoord;
|
use hex::prelude::*;
|
||||||
|
|
||||||
use super::chunk::Chunk;
|
|
||||||
|
|
||||||
pub struct MeshChunkData
|
pub struct MeshChunkData
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
pub mod chunk;
|
pub mod biome_map;
|
||||||
pub mod mesh_chunk;
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod map;
|
pub mod map;
|
||||||
pub mod biome_map;
|
|
||||||
pub mod map_utils;
|
pub mod map_utils;
|
||||||
|
pub mod mesh_chunk;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
pub use crate::consts::*;
|
pub use crate::consts::*;
|
||||||
pub use crate::map::chunk::*;
|
|
||||||
pub use crate::map::config::*;
|
pub use crate::map::config::*;
|
||||||
pub use crate::map::map::*;
|
pub use crate::map::map::*;
|
||||||
pub use crate::map::mesh_chunk::*;
|
pub use crate::map::mesh_chunk::*;
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ bevy_asset_loader = { version = "0.25.0", features = [
|
|||||||
"standard_dynamic_assets",
|
"standard_dynamic_assets",
|
||||||
"3d",
|
"3d",
|
||||||
] }
|
] }
|
||||||
|
hex = { path = "../../engine/hex" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
tracing = []
|
tracing = []
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
|
|
||||||
use bevy::prelude::Resource;
|
use bevy::prelude::Resource;
|
||||||
|
use hex::prelude::*;
|
||||||
use shared::building::BuildingIdentifier;
|
use shared::building::BuildingIdentifier;
|
||||||
use world_generation::hex_utils::HexCoord;
|
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct BuildQueue {
|
pub struct BuildQueue
|
||||||
|
{
|
||||||
pub queue: Vec<QueueEntry>,
|
pub queue: Vec<QueueEntry>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for BuildQueue {
|
impl Default for BuildQueue
|
||||||
fn default() -> Self {
|
{
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
Self {
|
Self {
|
||||||
queue: Default::default(),
|
queue: Default::default(),
|
||||||
}
|
}
|
||||||
@@ -17,7 +19,8 @@ impl Default for BuildQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
pub struct QueueEntry {
|
pub struct QueueEntry
|
||||||
|
{
|
||||||
pub building: BuildingIdentifier,
|
pub building: BuildingIdentifier,
|
||||||
pub pos: HexCoord,
|
pub pos: HexCoord,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,26 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use world_generation::{hex_utils::HexCoord, prelude::Chunk};
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
pub struct BuildingMap {
|
pub struct BuildingMap
|
||||||
|
{
|
||||||
pub chunks: Vec<BuildingChunk>,
|
pub chunks: Vec<BuildingChunk>,
|
||||||
pub size: UVec2,
|
pub size: UVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildingMap {
|
impl BuildingMap
|
||||||
pub fn new(size: UVec2) -> Self {
|
{
|
||||||
|
pub fn new(size: UVec2) -> Self
|
||||||
|
{
|
||||||
let mut db = BuildingMap {
|
let mut db = BuildingMap {
|
||||||
size,
|
size,
|
||||||
chunks: Vec::with_capacity(size.length_squared() as usize),
|
chunks: Vec::with_capacity(size.length_squared() as usize),
|
||||||
};
|
};
|
||||||
|
|
||||||
for y in 0..size.y as i32 {
|
for y in 0..size.y as i32
|
||||||
for x in 0..size.x as i32 {
|
{
|
||||||
|
for x in 0..size.x as i32
|
||||||
|
{
|
||||||
let offset = IVec2::new(x, y);
|
let offset = IVec2::new(x, y);
|
||||||
let index = (x + y * size.x as i32) as usize;
|
let index = (x + y * size.x as i32) as usize;
|
||||||
db.chunks.push(BuildingChunk::new(offset, index));
|
db.chunks.push(BuildingChunk::new(offset, index));
|
||||||
@@ -25,7 +30,8 @@ impl BuildingMap {
|
|||||||
return db;
|
return db;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_buildings_in_range(&self, coord: &HexCoord, radius: usize) -> Vec<&BuildingEntry> {
|
pub fn get_buildings_in_range(&self, coord: &HexCoord, radius: usize) -> Vec<&BuildingEntry>
|
||||||
|
{
|
||||||
assert!(radius != 0, "Radius cannot be zero");
|
assert!(radius != 0, "Radius cannot be zero");
|
||||||
|
|
||||||
let w = self.size.x as usize * Chunk::SIZE;
|
let w = self.size.x as usize * Chunk::SIZE;
|
||||||
@@ -34,10 +40,13 @@ impl BuildingMap {
|
|||||||
return self.get_buildings_in_coords(coords);
|
return self.get_buildings_in_coords(coords);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_buildings_in_coords(&self, coords: Vec<HexCoord>) -> Vec<&BuildingEntry> {
|
pub fn get_buildings_in_coords(&self, coords: Vec<HexCoord>) -> Vec<&BuildingEntry>
|
||||||
|
{
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for coord in &coords {
|
for coord in &coords
|
||||||
if let Some(buidling) = self.get_building(coord) {
|
{
|
||||||
|
if let Some(buidling) = self.get_building(coord)
|
||||||
|
{
|
||||||
result.push(buidling);
|
result.push(buidling);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,25 +54,30 @@ impl BuildingMap {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry> {
|
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry>
|
||||||
|
{
|
||||||
let chunk = &self.chunks[coord.to_chunk_index(self.size.x as usize)];
|
let chunk = &self.chunks[coord.to_chunk_index(self.size.x as usize)];
|
||||||
return chunk.get_building(coord);
|
return chunk.get_building(coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_building(&mut self, entry: BuildingEntry) {
|
pub fn add_building(&mut self, entry: BuildingEntry)
|
||||||
|
{
|
||||||
let chunk = &mut self.chunks[entry.coord.to_chunk_index(self.size.x as usize)];
|
let chunk = &mut self.chunks[entry.coord.to_chunk_index(self.size.x as usize)];
|
||||||
chunk.add_building(entry);
|
chunk.add_building(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BuildingChunk {
|
pub struct BuildingChunk
|
||||||
|
{
|
||||||
pub entries: Vec<BuildingEntry>,
|
pub entries: Vec<BuildingEntry>,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
pub offset: IVec2,
|
pub offset: IVec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildingChunk {
|
impl BuildingChunk
|
||||||
pub fn new(offset: IVec2, index: usize) -> Self {
|
{
|
||||||
|
pub fn new(offset: IVec2, index: usize) -> Self
|
||||||
|
{
|
||||||
return BuildingChunk {
|
return BuildingChunk {
|
||||||
entries: Vec::new(),
|
entries: Vec::new(),
|
||||||
index,
|
index,
|
||||||
@@ -71,16 +85,19 @@ impl BuildingChunk {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry> {
|
pub fn get_building(&self, coord: &HexCoord) -> Option<&BuildingEntry>
|
||||||
|
{
|
||||||
return self.entries.iter().find(|b| &b.coord == coord);
|
return self.entries.iter().find(|b| &b.coord == coord);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_building(&mut self, entry: BuildingEntry) {
|
pub fn add_building(&mut self, entry: BuildingEntry)
|
||||||
|
{
|
||||||
self.entries.push(entry);
|
self.entries.push(entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BuildingEntry {
|
pub struct BuildingEntry
|
||||||
|
{
|
||||||
pub coord: HexCoord,
|
pub coord: HexCoord,
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub is_main: bool,
|
pub is_main: bool,
|
||||||
@@ -89,8 +106,10 @@ pub struct BuildingEntry {
|
|||||||
pub child_entities: Option<Vec<Entity>>,
|
pub child_entities: Option<Vec<Entity>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BuildingEntry {
|
impl BuildingEntry
|
||||||
pub fn new(coord: HexCoord, entity: Entity) -> Self {
|
{
|
||||||
|
pub fn new(coord: HexCoord, entity: Entity) -> Self
|
||||||
|
{
|
||||||
return BuildingEntry {
|
return BuildingEntry {
|
||||||
coord,
|
coord,
|
||||||
entity,
|
entity,
|
||||||
@@ -101,7 +120,8 @@ impl BuildingEntry {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_children(coord: HexCoord, entity: Entity, children: Vec<Entity>) -> BuildingEntry {
|
pub fn new_with_children(coord: HexCoord, entity: Entity, children: Vec<Entity>) -> BuildingEntry
|
||||||
|
{
|
||||||
return BuildingEntry {
|
return BuildingEntry {
|
||||||
coord,
|
coord,
|
||||||
entity,
|
entity,
|
||||||
@@ -112,7 +132,8 @@ impl BuildingEntry {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_with_parent(coord: HexCoord, entity: Entity, main: Entity) -> BuildingEntry {
|
pub fn new_with_parent(coord: HexCoord, entity: Entity, main: Entity) -> BuildingEntry
|
||||||
|
{
|
||||||
return BuildingEntry {
|
return BuildingEntry {
|
||||||
coord,
|
coord,
|
||||||
entity,
|
entity,
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use bevy::math::{IVec2, Vec3Swizzles};
|
use bevy::math::{IVec2, Vec3Swizzles};
|
||||||
|
use hex::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use shared::coords::CoordsCollection;
|
use shared::coords::CoordsCollection;
|
||||||
use world_generation::hex_utils::HexCoord;
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
pub struct BuildingFootprint
|
pub struct BuildingFootprint
|
||||||
@@ -21,7 +21,7 @@ impl BuildingFootprint
|
|||||||
let n_points: Vec<IVec2> = self
|
let n_points: Vec<IVec2> = self
|
||||||
.footprint
|
.footprint
|
||||||
.iter()
|
.iter()
|
||||||
.flat_map(|p| HexCoord::from_hex(*p).get_neighbors())
|
.flat_map(|p| HexCoord::from_axial(*p).get_neighbors())
|
||||||
.map(|c| c.hex.xy())
|
.map(|c| c.hex.xy())
|
||||||
.filter(|p| !self.footprint.contains(p))
|
.filter(|p| !self.footprint.contains(p))
|
||||||
.collect();
|
.collect();
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ bevy_asset_loader = { version = "0.25.0", features = [
|
|||||||
] }
|
] }
|
||||||
ron = "0.12.0"
|
ron = "0.12.0"
|
||||||
image = "0.25.9"
|
image = "0.25.9"
|
||||||
|
hex = { path = "../../engine/hex" }
|
||||||
|
|
||||||
# bevy_lunex = "0.2.4"
|
# bevy_lunex = "0.2.4"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ use bevy::core_pipeline::prepass::DepthPrepass;
|
|||||||
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
|
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy::window::{CursorGrabMode, CursorOptions, PrimaryWindow};
|
use bevy::window::{CursorGrabMode, CursorOptions, PrimaryWindow};
|
||||||
|
use hex::prelude::*;
|
||||||
use shared::sets::GameplaySet;
|
use shared::sets::GameplaySet;
|
||||||
use shared::tags::MainCamera;
|
use shared::tags::MainCamera;
|
||||||
use world_generation::hex_utils::HexCoord;
|
|
||||||
use world_generation::prelude::Map;
|
use world_generation::prelude::Map;
|
||||||
use world_generation::states::GeneratorState;
|
use world_generation::states::GeneratorState;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use hex::prelude::*;
|
||||||
use rayon::str;
|
use rayon::str;
|
||||||
use world_generation::prelude::Chunk;
|
|
||||||
|
|
||||||
#[derive(Component, Reflect)]
|
#[derive(Component, Reflect)]
|
||||||
#[reflect(Component)]
|
#[reflect(Component)]
|
||||||
|
|||||||
@@ -4,13 +4,14 @@ use bevy::{light::NotShadowCaster, pbr::ExtendedMaterial, prelude::*};
|
|||||||
use bevy_asset_loader::prelude::*;
|
use bevy_asset_loader::prelude::*;
|
||||||
|
|
||||||
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
|
use bevy_inspector_egui::quick::ResourceInspectorPlugin;
|
||||||
|
use hex::prelude::*;
|
||||||
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefIterator, ParallelIterator};
|
||||||
use shared::states::{AssetLoadState, GameplayState, MenuState};
|
use shared::states::{AssetLoadState, GameplayState, MenuState};
|
||||||
|
|
||||||
use world_generation::{
|
use world_generation::{
|
||||||
biome_asset::{BiomeAsset, BiomeAssetPlugin},
|
biome_asset::{BiomeAsset, BiomeAssetPlugin},
|
||||||
biome_painter::*,
|
biome_painter::*,
|
||||||
heightmap::generate_heightmap,
|
heightmap::generate_heightmap,
|
||||||
hex_utils::{offset_to_index, SHORT_DIAGONAL},
|
|
||||||
map::biome_map::BiomeMap,
|
map::biome_map::BiomeMap,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
tile_manager::*,
|
tile_manager::*,
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use bevy::{
|
|||||||
mesh::Mesh,
|
mesh::Mesh,
|
||||||
};
|
};
|
||||||
use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
|
use bevy_rapier3d::geometry::{Collider, TriMeshFlags};
|
||||||
|
use hex::prelude::*;
|
||||||
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
use rayon::iter::{IntoParallelRefMutIterator, ParallelIterator};
|
||||||
use world_generation::{
|
use world_generation::{
|
||||||
biome_painter::BiomePainter,
|
biome_painter::BiomePainter,
|
||||||
@@ -14,8 +15,7 @@ use world_generation::{
|
|||||||
chunk_colliders::generate_chunk_collider,
|
chunk_colliders::generate_chunk_collider,
|
||||||
mesh_generator::{generate_chunk_mesh, generate_chunk_water_mesh},
|
mesh_generator::{generate_chunk_mesh, generate_chunk_water_mesh},
|
||||||
},
|
},
|
||||||
hex_utils::offset_to_world,
|
prelude::{Map, MeshChunkData},
|
||||||
prelude::{Chunk, Map, MeshChunkData},
|
|
||||||
tile_manager::TileAsset,
|
tile_manager::TileAsset,
|
||||||
tile_mapper::TileMapperAsset,
|
tile_mapper::TileMapperAsset,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,10 +1,12 @@
|
|||||||
use bevy::{prelude::*, window::PrimaryWindow};
|
use bevy::{prelude::*, window::PrimaryWindow};
|
||||||
use bevy_rapier3d::{plugin::ReadRapierContext, prelude::QueryFilter};
|
use bevy_rapier3d::{plugin::ReadRapierContext, prelude::QueryFilter};
|
||||||
|
use hex::prelude::*;
|
||||||
use shared::{
|
use shared::{
|
||||||
resources::{TileContact, TileUnderCursor},
|
resources::{TileContact, TileUnderCursor},
|
||||||
tags::MainCamera,
|
tags::MainCamera,
|
||||||
};
|
};
|
||||||
use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState};
|
use world_generation::{prelude::Map, states::GeneratorState};
|
||||||
|
|
||||||
pub struct TileSelectionPlugin;
|
pub struct TileSelectionPlugin;
|
||||||
|
|
||||||
impl Plugin for TileSelectionPlugin
|
impl Plugin for TileSelectionPlugin
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ edition = "2021"
|
|||||||
bevy = "0.18.0"
|
bevy = "0.18.0"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
world_generation = { path = "../../engine/world_generation" }
|
world_generation = { path = "../../engine/world_generation" }
|
||||||
|
hex = { path = "../../engine/hex" }
|
||||||
|
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use world_generation::hex_utils::HexCoord;
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Default, Debug, Reflect)]
|
#[derive(Default, Debug, Reflect)]
|
||||||
pub struct CoordsCollection
|
pub struct CoordsCollection
|
||||||
@@ -51,11 +51,11 @@ impl CoordsCollection
|
|||||||
|
|
||||||
pub fn get_coords(&self) -> Vec<HexCoord>
|
pub fn get_coords(&self) -> Vec<HexCoord>
|
||||||
{
|
{
|
||||||
let center = HexCoord::from_hex(self.origin);
|
let center = HexCoord::from_axial(self.origin);
|
||||||
return self
|
return self
|
||||||
.points
|
.points
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| HexCoord::from_hex(p + self.origin).rotate_around(¢er, self.rotation))
|
.map(|p| HexCoord::from_axial(p + self.origin).rotate_around(¢er, self.rotation))
|
||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use world_generation::hex_utils::*;
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub enum TileModifiedEvent {
|
pub enum TileModifiedEvent
|
||||||
|
{
|
||||||
HeightChanged(HexCoord, f32),
|
HeightChanged(HexCoord, f32),
|
||||||
TypeChanged(HexCoord, usize),
|
TypeChanged(HexCoord, usize),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Message)]
|
#[derive(Message)]
|
||||||
pub struct ChunkModifiedEvent {
|
pub struct ChunkModifiedEvent
|
||||||
|
{
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use world_generation::hex_utils::HexCoord;
|
use hex::prelude::*;
|
||||||
|
|
||||||
#[derive(Resource, Default)]
|
#[derive(Resource, Default)]
|
||||||
pub struct TileUnderCursor(pub Option<TileContact>);
|
pub struct TileUnderCursor(pub Option<TileContact>);
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct TileContact {
|
pub struct TileContact
|
||||||
|
{
|
||||||
pub tile: HexCoord,
|
pub tile: HexCoord,
|
||||||
pub point: Vec3,
|
pub point: Vec3,
|
||||||
pub surface: Vec3,
|
pub surface: Vec3,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TileContact {
|
impl TileContact
|
||||||
pub fn new(tile: HexCoord, contact: Vec3, surface: Vec3) -> Self {
|
{
|
||||||
|
pub fn new(tile: HexCoord, contact: Vec3, surface: Vec3) -> Self
|
||||||
|
{
|
||||||
return Self {
|
return Self {
|
||||||
tile,
|
tile,
|
||||||
point: contact,
|
point: contact,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ edition = "2021"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.18.0"
|
bevy = "0.18.0"
|
||||||
world_generation = { path = "../../engine/world_generation" }
|
world_generation = { path = "../../engine/world_generation" }
|
||||||
|
hex = { path = "../../engine/hex" }
|
||||||
shared = { path = "../shared" }
|
shared = { path = "../shared" }
|
||||||
bevy_rapier3d = "0.33.0"
|
bevy_rapier3d = "0.33.0"
|
||||||
serde = { version = "1.0.228", features = ["derive"] }
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use bevy::{ecs::world::CommandQueue, prelude::*, tasks::Task};
|
use bevy::{ecs::world::CommandQueue, prelude::*, tasks::Task};
|
||||||
|
use hex::prelude::*;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use world_generation::hex_utils::HexCoord;
|
|
||||||
|
|
||||||
#[derive(Component, Debug)]
|
#[derive(Component, Debug)]
|
||||||
pub struct Unit;
|
pub struct Unit;
|
||||||
@@ -13,7 +13,8 @@ pub struct LandUnit;
|
|||||||
pub struct NavalUnit;
|
pub struct NavalUnit;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
|
||||||
pub enum UnitDomain {
|
pub enum UnitDomain
|
||||||
|
{
|
||||||
Land,
|
Land,
|
||||||
Air,
|
Air,
|
||||||
Naval,
|
Naval,
|
||||||
|
|||||||
@@ -1,21 +1,27 @@
|
|||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
use hex::prelude::*;
|
||||||
use ordered_float::OrderedFloat;
|
use ordered_float::OrderedFloat;
|
||||||
use world_generation::{hex_utils::HexCoord, prelude::Map};
|
use world_generation::prelude::Map;
|
||||||
|
|
||||||
#[derive(Clone, Resource)]
|
#[derive(Clone, Resource)]
|
||||||
pub struct NavData {
|
pub struct NavData
|
||||||
|
{
|
||||||
pub tiles: Vec<NavTile>,
|
pub tiles: Vec<NavTile>,
|
||||||
pub map_height: usize,
|
pub map_height: usize,
|
||||||
pub map_width: usize,
|
pub map_width: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavData {
|
impl NavData
|
||||||
pub fn get_neighbors(&self, coord: &HexCoord) -> Vec<(HexCoord, OrderedFloat<f32>)> {
|
{
|
||||||
|
pub fn get_neighbors(&self, coord: &HexCoord) -> Vec<(HexCoord, OrderedFloat<f32>)>
|
||||||
|
{
|
||||||
let mut neighbors = Vec::with_capacity(6);
|
let mut neighbors = Vec::with_capacity(6);
|
||||||
let cur_height = self.get_height(coord);
|
let cur_height = self.get_height(coord);
|
||||||
for i in 0..6 {
|
for i in 0..6
|
||||||
|
{
|
||||||
let n = coord.get_neighbor(i);
|
let n = coord.get_neighbor(i);
|
||||||
if !self.is_in_bounds(&n) {
|
if !self.is_in_bounds(&n)
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let n_height = self.get_height(&n);
|
let n_height = self.get_height(&n);
|
||||||
@@ -23,26 +29,32 @@ impl NavData {
|
|||||||
}
|
}
|
||||||
return neighbors;
|
return neighbors;
|
||||||
}
|
}
|
||||||
pub fn get(&self, coord: &HexCoord) -> &NavTile {
|
pub fn get(&self, coord: &HexCoord) -> &NavTile
|
||||||
|
{
|
||||||
return &self.tiles[coord.to_index(self.map_width)];
|
return &self.tiles[coord.to_index(self.map_width)];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_height(&self, coord: &HexCoord) -> f32 {
|
pub fn get_height(&self, coord: &HexCoord) -> f32
|
||||||
|
{
|
||||||
return self.tiles[coord.to_index(self.map_width)].height;
|
return self.tiles[coord.to_index(self.map_width)].height;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
|
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool
|
||||||
|
{
|
||||||
return pos.is_in_bounds(self.map_height, self.map_width);
|
return pos.is_in_bounds(self.map_height, self.map_width);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build(map: &Map) -> NavData {
|
pub fn build(map: &Map) -> NavData
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _path_span = info_span!("Build Nav Data").entered();
|
let _path_span = info_span!("Build Nav Data").entered();
|
||||||
let mut tiles = Vec::with_capacity(map.get_tile_count());
|
let mut tiles = Vec::with_capacity(map.get_tile_count());
|
||||||
let h = map.get_tile_height();
|
let h = map.get_tile_height();
|
||||||
let w = map.get_tile_width();
|
let w = map.get_tile_width();
|
||||||
for y in 0..h {
|
for y in 0..h
|
||||||
for x in 0..w {
|
{
|
||||||
|
for x in 0..w
|
||||||
|
{
|
||||||
let coord = HexCoord::from_grid_pos(x, y);
|
let coord = HexCoord::from_grid_pos(x, y);
|
||||||
let height = map.sample_height(&coord);
|
let height = map.sample_height(&coord);
|
||||||
let tile = NavTile {
|
let tile = NavTile {
|
||||||
@@ -61,13 +73,16 @@ impl NavData {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, map: &Map) {
|
pub fn update(&mut self, map: &Map)
|
||||||
|
{
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _path_span = info_span!("Update Nav Data").entered();
|
let _path_span = info_span!("Update Nav Data").entered();
|
||||||
let h = map.get_tile_height();
|
let h = map.get_tile_height();
|
||||||
let w = map.get_tile_width();
|
let w = map.get_tile_width();
|
||||||
for y in 0..h {
|
for y in 0..h
|
||||||
for x in 0..w {
|
{
|
||||||
|
for x in 0..w
|
||||||
|
{
|
||||||
let coord = HexCoord::from_grid_pos(x, y);
|
let coord = HexCoord::from_grid_pos(x, y);
|
||||||
let height = map.sample_height(&coord);
|
let height = map.sample_height(&coord);
|
||||||
let tile = NavTile {
|
let tile = NavTile {
|
||||||
@@ -79,7 +94,8 @@ impl NavData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn update_tile(&mut self, coord: &HexCoord, height: f32, move_cost: f32) {
|
pub fn update_tile(&mut self, coord: &HexCoord, height: f32, move_cost: f32)
|
||||||
|
{
|
||||||
let tile = &mut self.tiles[coord.to_index(self.map_width)];
|
let tile = &mut self.tiles[coord.to_index(self.map_width)];
|
||||||
tile.move_cost = move_cost;
|
tile.move_cost = move_cost;
|
||||||
tile.height = height;
|
tile.height = height;
|
||||||
@@ -87,14 +103,17 @@ impl NavData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct NavTile {
|
pub struct NavTile
|
||||||
|
{
|
||||||
pub height: f32,
|
pub height: f32,
|
||||||
pub move_cost: f32,
|
pub move_cost: f32,
|
||||||
pub coord: HexCoord,
|
pub coord: HexCoord,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NavTile {
|
impl NavTile
|
||||||
pub fn calculate_heuristic(&self, to: &HexCoord) -> OrderedFloat<f32> {
|
{
|
||||||
|
pub fn calculate_heuristic(&self, to: &HexCoord) -> OrderedFloat<f32>
|
||||||
|
{
|
||||||
return (self.coord.distance(to) as f32).into();
|
return (self.coord.distance(to) as f32).into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,9 +5,10 @@ use bevy::{
|
|||||||
prelude::*,
|
prelude::*,
|
||||||
tasks::{futures, AsyncComputeTaskPool},
|
tasks::{futures, AsyncComputeTaskPool},
|
||||||
};
|
};
|
||||||
|
use hex::prelude::*;
|
||||||
use pathfinding::prelude::astar;
|
use pathfinding::prelude::astar;
|
||||||
use shared::{events::TileModifiedEvent, resources::TileUnderCursor, sets::GameplaySet};
|
use shared::{events::TileModifiedEvent, resources::TileUnderCursor, sets::GameplaySet};
|
||||||
use world_generation::{hex_utils::HexCoord, prelude::Map, states::GeneratorState};
|
use world_generation::{prelude::Map, states::GeneratorState};
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
use crate::units_debug_plugin::UnitsDebugPlugin;
|
use crate::units_debug_plugin::UnitsDebugPlugin;
|
||||||
@@ -20,8 +21,10 @@ use crate::{
|
|||||||
|
|
||||||
pub struct UnitsPlugin;
|
pub struct UnitsPlugin;
|
||||||
|
|
||||||
impl Plugin for UnitsPlugin {
|
impl Plugin for UnitsPlugin
|
||||||
fn build(&self, app: &mut App) {
|
{
|
||||||
|
fn build(&self, app: &mut App)
|
||||||
|
{
|
||||||
app.init_resource::<PathBatchId>();
|
app.init_resource::<PathBatchId>();
|
||||||
app.add_plugins(UnitAssetPlugin);
|
app.add_plugins(UnitAssetPlugin);
|
||||||
|
|
||||||
@@ -40,15 +43,20 @@ impl Plugin for UnitsPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_navdata(mut commands: Commands, map: Res<Map>) {
|
fn build_navdata(mut commands: Commands, map: Res<Map>)
|
||||||
|
{
|
||||||
let nav_data = NavData::build(&map);
|
let nav_data = NavData::build(&map);
|
||||||
commands.insert_resource(nav_data);
|
commands.insert_resource(nav_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_navdata(mut tile_updates: MessageReader<TileModifiedEvent>, mut nav_data: ResMut<NavData>) {
|
fn update_navdata(mut tile_updates: MessageReader<TileModifiedEvent>, mut nav_data: ResMut<NavData>)
|
||||||
for event in tile_updates.read() {
|
{
|
||||||
match event {
|
for event in tile_updates.read()
|
||||||
TileModifiedEvent::HeightChanged(coord, new_height) => {
|
{
|
||||||
|
match event
|
||||||
|
{
|
||||||
|
TileModifiedEvent::HeightChanged(coord, new_height) =>
|
||||||
|
{
|
||||||
nav_data.update_tile(coord, *new_height, 1.0);
|
nav_data.update_tile(coord, *new_height, 1.0);
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
@@ -56,6 +64,7 @@ fn update_navdata(mut tile_updates: MessageReader<TileModifiedEvent>, mut nav_da
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(unused)]
|
||||||
fn units_control(tile_under_cursor: Res<TileUnderCursor>) {}
|
fn units_control(tile_under_cursor: Res<TileUnderCursor>) {}
|
||||||
|
|
||||||
fn move_unit(
|
fn move_unit(
|
||||||
@@ -63,22 +72,27 @@ fn move_unit(
|
|||||||
time: Res<Time>,
|
time: Res<Time>,
|
||||||
map: Res<Map>,
|
map: Res<Map>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
)
|
||||||
for (mut t, mut path, entity) in units.iter_mut() {
|
{
|
||||||
if path.1 >= path.0.len() {
|
for (mut t, mut path, entity) in units.iter_mut()
|
||||||
|
{
|
||||||
|
if path.1 >= path.0.len()
|
||||||
|
{
|
||||||
commands.entity(entity).remove::<Path>();
|
commands.entity(entity).remove::<Path>();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let p = path.0[path.1];
|
let p = path.0[path.1];
|
||||||
let d = p - t.translation;
|
let d = p - t.translation;
|
||||||
if d.length() < 0.1 {
|
if d.length() < 0.1
|
||||||
|
{
|
||||||
path.1 += 1;
|
path.1 += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let vel = d.normalize() * 10.0 * time.delta_secs();
|
let vel = d.normalize() * 10.0 * time.delta_secs();
|
||||||
t.translation += vel;
|
t.translation += vel;
|
||||||
let coord = HexCoord::from_world_pos(t.translation);
|
let coord = HexCoord::from_world_pos(t.translation);
|
||||||
if map.is_in_bounds(&coord) {
|
if map.is_in_bounds(&coord)
|
||||||
|
{
|
||||||
t.translation.y = map.sample_height(&coord);
|
t.translation.y = map.sample_height(&coord);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,22 +104,28 @@ fn dispatch_path_requests(
|
|||||||
nav_data: Res<NavData>,
|
nav_data: Res<NavData>,
|
||||||
mut batch_id: ResMut<PathBatchId>,
|
mut batch_id: ResMut<PathBatchId>,
|
||||||
mut commands: Commands,
|
mut commands: Commands,
|
||||||
) {
|
)
|
||||||
if units.is_empty() {
|
{
|
||||||
|
if units.is_empty()
|
||||||
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let mut groups: HashMap<HexCoord, Vec<PathRequest>> = HashMap::new();
|
let mut groups: HashMap<HexCoord, Vec<PathRequest>> = HashMap::new();
|
||||||
|
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _group_span = info_span!("Grouping").entered();
|
let _group_span = info_span!("Grouping").entered();
|
||||||
for (transform, target, entity) in units.iter() {
|
for (transform, target, entity) in units.iter()
|
||||||
|
{
|
||||||
let req = PathRequest {
|
let req = PathRequest {
|
||||||
entity,
|
entity,
|
||||||
from: HexCoord::from_world_pos(transform.translation),
|
from: HexCoord::from_world_pos(transform.translation),
|
||||||
};
|
};
|
||||||
if let Some(group) = groups.get_mut(&target.0) {
|
if let Some(group) = groups.get_mut(&target.0)
|
||||||
|
{
|
||||||
group.push(req);
|
group.push(req);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
groups.insert(target.0, vec![req]);
|
groups.insert(target.0, vec![req]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,11 +133,13 @@ fn dispatch_path_requests(
|
|||||||
drop(_group_span);
|
drop(_group_span);
|
||||||
|
|
||||||
let pool = AsyncComputeTaskPool::get();
|
let pool = AsyncComputeTaskPool::get();
|
||||||
for (target, units) in groups {
|
for (target, units) in groups
|
||||||
|
{
|
||||||
let id = batch_id.0;
|
let id = batch_id.0;
|
||||||
batch_id.0 += 1;
|
batch_id.0 += 1;
|
||||||
|
|
||||||
for req in &units {
|
for req in &units
|
||||||
|
{
|
||||||
commands
|
commands
|
||||||
.entity(req.entity)
|
.entity(req.entity)
|
||||||
.insert(PathTaskPending(id))
|
.insert(PathTaskPending(id))
|
||||||
@@ -136,17 +158,21 @@ fn dispatch_path_requests(
|
|||||||
let batch_task = pool.spawn(async move {
|
let batch_task = pool.spawn(async move {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
let mut queue = CommandQueue::default();
|
let mut queue = CommandQueue::default();
|
||||||
for entitiy_req in req.entities {
|
for entitiy_req in req.entities
|
||||||
|
{
|
||||||
let dst = req.destination[i];
|
let dst = req.destination[i];
|
||||||
i += 1;
|
i += 1;
|
||||||
#[cfg(feature = "tracing")]
|
#[cfg(feature = "tracing")]
|
||||||
let _path_span = info_span!("Path Finding").entered();
|
let _path_span = info_span!("Path Finding").entered();
|
||||||
if let Some(path) = calculate_path(&entitiy_req.from, &dst, &local_nav_data) {
|
if let Some(path) = calculate_path(&entitiy_req.from, &dst, &local_nav_data)
|
||||||
|
{
|
||||||
queue.push(move |world: &mut World| {
|
queue.push(move |world: &mut World| {
|
||||||
let mut unit_e = world.entity_mut(entitiy_req.entity);
|
let mut unit_e = world.entity_mut(entitiy_req.entity);
|
||||||
|
|
||||||
if let Some(pending_task) = unit_e.get::<PathTaskPending>() {
|
if let Some(pending_task) = unit_e.get::<PathTaskPending>()
|
||||||
if pending_task.0 == id {
|
{
|
||||||
|
if pending_task.0 == id
|
||||||
|
{
|
||||||
unit_e.insert(path);
|
unit_e.insert(path);
|
||||||
unit_e.remove::<PathTaskPending>();
|
unit_e.remove::<PathTaskPending>();
|
||||||
}
|
}
|
||||||
@@ -154,7 +180,8 @@ fn dispatch_path_requests(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if queue.is_empty() {
|
if queue.is_empty()
|
||||||
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
return Some(queue);
|
return Some(queue);
|
||||||
@@ -163,26 +190,36 @@ fn dispatch_path_requests(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_end_points(coord: &HexCoord, count: usize, map: &Map) -> Vec<HexCoord> {
|
fn get_end_points(coord: &HexCoord, count: usize, map: &Map) -> Vec<HexCoord>
|
||||||
|
{
|
||||||
let mut result = Vec::with_capacity(count);
|
let mut result = Vec::with_capacity(count);
|
||||||
if count == 1 {
|
if count == 1
|
||||||
|
{
|
||||||
return vec![*coord];
|
return vec![*coord];
|
||||||
}
|
}
|
||||||
result.push(*coord);
|
result.push(*coord);
|
||||||
let mut r = 1;
|
let mut r = 1;
|
||||||
while result.len() < count {
|
while result.len() < count
|
||||||
|
{
|
||||||
let tiles = HexCoord::select_ring(coord, r);
|
let tiles = HexCoord::select_ring(coord, r);
|
||||||
let needed = count - result.len();
|
let needed = count - result.len();
|
||||||
if needed >= tiles.len() {
|
if needed >= tiles.len()
|
||||||
for t in tiles {
|
{
|
||||||
if map.is_in_bounds(&t) {
|
for t in tiles
|
||||||
|
{
|
||||||
|
if map.is_in_bounds(&t)
|
||||||
|
{
|
||||||
result.push(t);
|
result.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
for i in 0..needed {
|
else
|
||||||
|
{
|
||||||
|
for i in 0..needed
|
||||||
|
{
|
||||||
let t = tiles[i];
|
let t = tiles[i];
|
||||||
if map.is_in_bounds(&t) {
|
if map.is_in_bounds(&t)
|
||||||
|
{
|
||||||
result.push(t);
|
result.push(t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -193,10 +230,14 @@ fn get_end_points(coord: &HexCoord, count: usize, map: &Map) -> Vec<HexCoord> {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_path_task(mut tasks: Query<(&mut PathTask, Entity)>, mut commands: Commands) {
|
fn resolve_path_task(mut tasks: Query<(&mut PathTask, Entity)>, mut commands: Commands)
|
||||||
for (mut task, entity) in tasks.iter_mut() {
|
{
|
||||||
if let Some(c) = futures::check_ready(&mut task.0) {
|
for (mut task, entity) in tasks.iter_mut()
|
||||||
if let Some(mut queue) = c {
|
{
|
||||||
|
if let Some(c) = futures::check_ready(&mut task.0)
|
||||||
|
{
|
||||||
|
if let Some(mut queue) = c
|
||||||
|
{
|
||||||
commands.append(&mut queue);
|
commands.append(&mut queue);
|
||||||
}
|
}
|
||||||
commands.entity(entity).despawn();
|
commands.entity(entity).despawn();
|
||||||
@@ -204,32 +245,38 @@ fn resolve_path_task(mut tasks: Query<(&mut PathTask, Entity)>, mut commands: Co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_path(from: &HexCoord, to: &HexCoord, nav: &NavData) -> Option<Path> {
|
fn calculate_path(from: &HexCoord, to: &HexCoord, nav: &NavData) -> Option<Path>
|
||||||
|
{
|
||||||
let path = astar(
|
let path = astar(
|
||||||
from,
|
from,
|
||||||
|n| nav.get_neighbors(n),
|
|n| nav.get_neighbors(n),
|
||||||
|n| nav.get(n).calculate_heuristic(to),
|
|n| nav.get(n).calculate_heuristic(to),
|
||||||
|n| n == to,
|
|n| n == to,
|
||||||
);
|
);
|
||||||
if let Some((nodes, _cost)) = path {
|
if let Some((nodes, _cost)) = path
|
||||||
|
{
|
||||||
let result: Vec<_> = nodes.iter().map(|f| f.to_world(nav.get_height(f))).collect();
|
let result: Vec<_> = nodes.iter().map(|f| f.to_world(nav.get_height(f))).collect();
|
||||||
return Some(Path(result, 1));
|
return Some(Path(result, 1));
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct PathRequest {
|
struct PathRequest
|
||||||
|
{
|
||||||
pub entity: Entity,
|
pub entity: Entity,
|
||||||
pub from: HexCoord,
|
pub from: HexCoord,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct BatchPathRequest {
|
struct BatchPathRequest
|
||||||
|
{
|
||||||
pub entities: Vec<PathRequest>,
|
pub entities: Vec<PathRequest>,
|
||||||
pub destination: Vec<HexCoord>,
|
pub destination: Vec<HexCoord>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BatchPathRequest {
|
impl BatchPathRequest
|
||||||
pub fn new(entities: Vec<PathRequest>, dst: Vec<HexCoord>) -> Self {
|
{
|
||||||
|
pub fn new(entities: Vec<PathRequest>, dst: Vec<HexCoord>) -> Self
|
||||||
|
{
|
||||||
return Self {
|
return Self {
|
||||||
destination: dst,
|
destination: dst,
|
||||||
entities,
|
entities,
|
||||||
|
|||||||
Reference in New Issue
Block a user