various fixes to map size calculations

This commit is contained in:
2024-05-05 11:18:44 -04:00
parent 7b6cae39b7
commit cd4c9f2acf
6 changed files with 121 additions and 60 deletions

View File

@@ -2,7 +2,10 @@ use crate::prelude::Chunk;
use bevy::prelude::*; use bevy::prelude::*;
pub const OUTER_RADIUS: f32 = 1.; pub const OUTER_RADIUS: f32 = 1.;
pub const INNER_RADIUS: f32 = OUTER_RADIUS * 0.866025404; 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 { pub fn offset3d_to_world(offset: Vec3) -> Vec3 {
let x = (offset.x + (offset.z * 0.5) - (offset.z / 2.).floor()) * (INNER_RADIUS * 2.); let x = (offset.x + (offset.z * 0.5) - (offset.z / 2.).floor()) * (INNER_RADIUS * 2.);
@@ -41,11 +44,11 @@ pub fn world_to_offset_pos(world_pos: Vec3) -> IVec2 {
return IVec2::new(ox, oz); return IVec2::new(ox, oz);
} }
pub fn tile_to_world_distance(dist: i32) -> f32 { pub fn tile_to_world_distance(dist: u32) -> f32 {
return dist as f32 * (2. * INNER_RADIUS); return dist as f32 * (2. * INNER_RADIUS);
} }
pub fn get_tile_count(radius: i32) -> i32 { pub fn get_tile_count(radius: u32) -> u32 {
return 1 + 3 * (radius + 1) * radius; return 1 + 3 * (radius + 1) * radius;
} }

View File

@@ -8,7 +8,7 @@ pub mod tile_manager;
pub mod tile_mapper; pub mod tile_mapper;
pub mod prelude { pub mod prelude {
use crate::hex_utils::{tile_to_world_distance, HexCoord, INNER_RADIUS, OUTER_RADIUS}; use crate::hex_utils::{tile_to_world_distance, HexCoord, INNER_RADIUS, OUTER_RADIUS, SHORT_DIAGONAL};
use bevy::math::{IVec2, UVec2, Vec2, Vec3}; use bevy::math::{IVec2, UVec2, Vec2, Vec3};
use bevy::prelude::Resource; use bevy::prelude::Resource;
use bevy::prelude::*; use bevy::prelude::*;
@@ -77,6 +77,9 @@ pub mod prelude {
impl Chunk { impl Chunk {
pub const SIZE: usize = 64; pub const SIZE: usize = 64;
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);
} }
#[derive(Resource)] #[derive(Resource)]
@@ -111,6 +114,10 @@ pub mod prelude {
return chunk.heights[pos.to_chunk_local_index()]; return chunk.heights[pos.to_chunk_local_index()];
} }
pub fn is_in_bounds(&self, pos: &HexCoord) -> bool {
return pos.is_in_bounds(self.height * Chunk::SIZE, self.width * Chunk::SIZE);
}
pub fn get_moisture(&self, pos: &HexCoord) -> f32 { pub fn get_moisture(&self, pos: &HexCoord) -> f32 {
let chunk = &self.chunks[pos.to_chunk_index(self.width)]; let chunk = &self.chunks[pos.to_chunk_index(self.width)];
return chunk.moisture[pos.to_chunk_local_index()]; return chunk.moisture[pos.to_chunk_local_index()];
@@ -122,20 +129,20 @@ pub mod prelude {
} }
pub fn get_center(&self) -> Vec3 { pub fn get_center(&self) -> Vec3 {
let w = self.width * Chunk::SIZE; let w = self.get_world_width();
let h = self.height * Chunk::SIZE; let h = self.get_world_height();
return Vec3::new( return Vec3::new(w / 2., self.sea_level, h / 2.);
tile_to_world_distance(w as i32 / 2),
self.sea_level,
tile_to_world_distance(h as i32 / 2),
);
} }
pub fn get_world_width(&self) -> f32 { pub fn get_world_width(&self) -> f32 {
return tile_to_world_distance((self.width * Chunk::SIZE) as i32); return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
} }
pub fn get_world_height(&self) -> f32 { pub fn get_world_height(&self) -> f32 {
return tile_to_world_distance((self.height * Chunk::SIZE) as i32); return (self.height * Chunk::SIZE) as f32 * 1.5;
}
pub fn get_world_size(&self) -> Vec2 {
return Vec2::new(self.get_world_width(), self.get_world_height());
} }
} }
pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute = pub const ATTRIBUTE_PACKED_VERTEX_DATA: MeshVertexAttribute =

View File

@@ -36,7 +36,6 @@ fn setup(mut commands: Commands, mut msaa: ResMut<Msaa>) {
PhosCamera::default(), PhosCamera::default(),
PhosCameraTargets::default(), PhosCameraTargets::default(),
)) ))
.insert(ScreenSpaceAmbientOcclusionBundle::default())
.insert(TemporalAntiAliasBundle::default()); .insert(TemporalAntiAliasBundle::default());
*msaa = Msaa::Off; *msaa = Msaa::Off;
@@ -147,12 +146,13 @@ fn rts_camera_system(
cam_move.z = -1.; cam_move.z = -1.;
} }
if key.pressed(KeyCode::ShiftLeft) { let move_speed = if key.pressed(KeyCode::ShiftLeft) {
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds() * 2.; cam_cfg.speed * 2.
} else { } else {
cam_move = cam_move.normalize_or_zero() * cam_cfg.speed * time.delta_seconds(); cam_cfg.speed
} };
cam_move = cam_move.normalize_or_zero() * move_speed * time.delta_seconds();
cam_pos -= cam_move; cam_pos -= cam_move;
let mut scroll = 0.0; let mut scroll = 0.0;
@@ -163,22 +163,13 @@ fn rts_camera_system(
} }
} }
let ground_height = sample_ground(cam.translation, &heightmap);
cam_targets.height -= scroll; cam_targets.height -= scroll;
if cam_targets.height > cam_cfg.max_height { if cam_targets.height > cam_cfg.max_height {
cam_targets.height = cam_cfg.max_height; cam_targets.height = cam_cfg.max_height;
} }
let tile_under = HexCoord::from_world_pos(cam.translation);
let neighbors = heightmap.get_neighbors(&tile_under);
let mut ground_height = heightmap.sample_height(&tile_under);
for n in neighbors {
if let Some(h) = n {
if h > ground_height {
ground_height = h;
}
}
}
let min_height = ground_height + cam_cfg.min_height; let min_height = ground_height + cam_cfg.min_height;
if min_height != cam_targets.last_height { if min_height != cam_targets.last_height {
@@ -218,4 +209,35 @@ fn rts_camera_system(
cam.translation = cam_pos; cam.translation = cam_pos;
} }
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {} fn sample_ground(pos: Vec3, heightmap: &Map) -> f32 {
let tile_under = HexCoord::from_world_pos(pos);
let neighbors = heightmap.get_neighbors(&tile_under);
let mut ground_height = if heightmap.is_in_bounds(&tile_under) {
heightmap.sample_height(&tile_under)
} else {
heightmap.sea_level
};
for n in neighbors {
if let Some(h) = n {
if h > ground_height {
ground_height = h;
}
}
}
if ground_height < heightmap.sea_level {
ground_height = heightmap.sea_level;
}
return ground_height;
}
fn limit_camera_bounds(mut cam_query: Query<(&mut Transform, &CameraBounds)>) {
let (mut tranform, bounds) = cam_query.single_mut();
let mut pos = tranform.translation;
pos.x = pos.x.clamp(bounds.min.x, bounds.max.x);
pos.z = pos.z.clamp(bounds.min.y, bounds.max.y);
tranform.translation = pos;
}

View File

@@ -1,4 +1,8 @@
use bevy::prelude::*; use bevy::prelude::*;
use world_generation::{
hex_utils::{tile_to_world_distance, SHORT_DIAGONAL},
prelude::Chunk,
};
#[derive(Component, Reflect)] #[derive(Component, Reflect)]
#[reflect(Component)] #[reflect(Component)]
@@ -15,8 +19,8 @@ impl Default for PhosCamera {
fn default() -> Self { fn default() -> Self {
Self { Self {
min_height: 10., min_height: 10.,
max_height: 100., max_height: 120.,
speed: 20., speed: 30.,
zoom_speed: 0.3, zoom_speed: 0.3,
min_angle: (20. as f32).to_radians(), min_angle: (20. as f32).to_radians(),
max_angle: 1., max_angle: 1.,
@@ -24,14 +28,27 @@ impl Default for PhosCamera {
} }
} }
#[derive(Component, Default)] #[derive(Component)]
pub struct PhosCameraTargets { pub struct PhosCameraTargets {
pub height: f32, pub height: f32,
pub forward: Vec3,
pub last_height: f32, pub last_height: f32,
pub anim_time: f32, pub anim_time: f32,
pub rotate_time: f32, pub rotate_time: f32,
} }
impl Default for PhosCameraTargets {
fn default() -> Self {
Self {
height: Default::default(),
forward: Vec3::Z,
last_height: Default::default(),
anim_time: Default::default(),
rotate_time: Default::default(),
}
}
}
#[derive(Component, Default)] #[derive(Component, Default)]
pub struct CameraBounds { pub struct CameraBounds {
pub min: Vec2, pub min: Vec2,
@@ -40,9 +57,13 @@ pub struct CameraBounds {
impl CameraBounds { impl CameraBounds {
pub fn from_size(size: UVec2) -> Self { pub fn from_size(size: UVec2) -> Self {
let padding = Chunk::WORLD_SIZE;
return Self { return Self {
min: Vec2::ZERO, min: Vec2::ZERO - padding,
max: size.as_vec2(), max: Vec2::new(
(size.x as usize * Chunk::SIZE) as f32 * SHORT_DIAGONAL,
(size.y * Chunk::SIZE as u32) as f32 * 1.5,
) + padding,
}; };
} }
} }

View File

@@ -6,7 +6,7 @@ use world_generation::{
biome_painter::*, biome_painter::*,
chunk_colliders::generate_chunk_collider, chunk_colliders::generate_chunk_collider,
heightmap::generate_heightmap, heightmap::generate_heightmap,
hex_utils::{offset_to_world, tile_to_world_distance}, hex_utils::{offset_to_world, SHORT_DIAGONAL},
mesh_generator::generate_chunk_mesh, mesh_generator::generate_chunk_mesh,
prelude::*, prelude::*,
tile_manager::*, tile_manager::*,
@@ -39,11 +39,23 @@ impl Plugin for MapInitPlugin {
} }
} }
fn load_textures(mut commands: Commands, asset_server: Res<AssetServer>) { fn load_textures(
mut commands: Commands,
asset_server: Res<AssetServer>,
mut standard_materials: ResMut<Assets<StandardMaterial>>,
) {
let main_tex = asset_server.load("textures/world/stack.png"); let main_tex = asset_server.load("textures/world/stack.png");
let water_material = standard_materials.add(StandardMaterial {
base_color: Color::AQUAMARINE.with_a(0.5),
alpha_mode: AlphaMode::Blend,
..default()
});
commands.insert_resource(ChunkAtlas { commands.insert_resource(ChunkAtlas {
handle: main_tex.clone(), handle: main_tex.clone(),
is_loaded: false, is_loaded: false,
chunk_material_handle: Handle::default(),
water_material: water_material,
}); });
} }
#[derive(Resource)] #[derive(Resource)]
@@ -62,6 +74,7 @@ fn finalize_texture(
painter: Res<Painter>, painter: Res<Painter>,
painter_load: Res<BiomePainterLoadState>, painter_load: Res<BiomePainterLoadState>,
tile_load: Res<TileAssetLoadState>, tile_load: Res<TileAssetLoadState>,
mut chunk_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, ChunkMaterial>>>,
mapper_load: Res<TileMapperLoadState>, mapper_load: Res<TileMapperLoadState>,
) { ) {
if atlas.is_loaded { if atlas.is_loaded {
@@ -84,6 +97,13 @@ fn finalize_texture(
image.reinterpret_stacked_2d_as_array(array_layers); image.reinterpret_stacked_2d_as_array(array_layers);
atlas.is_loaded = true; atlas.is_loaded = true;
let chunk_material = chunk_materials.add(ExtendedMaterial {
base: StandardMaterial::default(),
extension: ChunkMaterial {
array_texture: atlas.handle.clone(),
},
});
atlas.chunk_material_handle = chunk_material;
map.ready = true; map.ready = true;
map.regenerate = true; map.regenerate = true;
} }
@@ -160,25 +180,18 @@ fn create_map(mut commands: Commands, mut cam: Query<(&mut Transform, Entity), W
}; };
let heightmap = generate_heightmap(&config, 4); let heightmap = generate_heightmap(&config, 4);
commands.insert_resource(heightmap);
let (mut cam_t, cam_entity) = cam.single_mut(); let (mut cam_t, cam_entity) = cam.single_mut();
cam_t.translation = Vec3::new( cam_t.translation = heightmap.get_center();
tile_to_world_distance((config.size.x as i32 * Chunk::SIZE as i32) / 2),
cam_t.translation.y,
tile_to_world_distance((config.size.y as i32 * Chunk::SIZE as i32) / 2),
);
commands.entity(cam_entity).insert(CameraBounds::from_size(config.size)); commands.entity(cam_entity).insert(CameraBounds::from_size(config.size));
commands.insert_resource(heightmap);
commands.insert_resource(config); commands.insert_resource(config);
} }
fn spawn_map( fn spawn_map(
heightmap: Res<Map>, heightmap: Res<Map>,
mut commands: Commands, mut commands: Commands,
mut chunk_materials: ResMut<Assets<ExtendedMaterial<StandardMaterial, ChunkMaterial>>>,
mut standard_materials: ResMut<Assets<StandardMaterial>>,
mut meshes: ResMut<Assets<Mesh>>, mut meshes: ResMut<Assets<Mesh>>,
atlas: Res<ChunkAtlas>, atlas: Res<ChunkAtlas>,
mut map: ResMut<PhosMap>, mut map: ResMut<PhosMap>,
@@ -192,12 +205,6 @@ fn spawn_map(
} }
let b_painter = biome_painters.get(painter.0.clone()); let b_painter = biome_painters.get(painter.0.clone());
map.regenerate = false; map.regenerate = false;
let chunk_material = chunk_materials.add(ExtendedMaterial {
base: StandardMaterial::default(),
extension: ChunkMaterial {
array_texture: atlas.handle.clone(),
},
});
let cur_painter = b_painter.unwrap(); let cur_painter = b_painter.unwrap();
@@ -219,15 +226,15 @@ fn spawn_map(
commands.spawn(( commands.spawn((
MaterialMeshBundle { MaterialMeshBundle {
mesh: meshes.add(mesh), mesh: meshes.add(mesh),
material: chunk_material.clone(), material: atlas.chunk_material_handle.clone(),
transform: Transform::from_translation(pos), transform: Transform::from_translation(pos),
..default() ..default()
}, },
PhosChunk, PhosChunk,
RenderDistanceVisibility::default().with_offset(Vec3::new( RenderDistanceVisibility::default().with_offset(Vec3::new(
tile_to_world_distance(Chunk::SIZE as i32 / 2), (Chunk::SIZE / 2) as f32 * SHORT_DIAGONAL,
0., 0.,
tile_to_world_distance(Chunk::SIZE as i32 / 2), (Chunk::SIZE / 2) as f32 * 1.5,
)), )),
Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES), Collider::trimesh_with_flags(col_verts, col_indicies, TriMeshFlags::MERGE_DUPLICATE_VERTICES),
)); ));
@@ -240,11 +247,7 @@ fn spawn_map(
.mesh() .mesh()
.size(heightmap.get_world_width(), heightmap.get_world_height()), .size(heightmap.get_world_width(), heightmap.get_world_height()),
), ),
material: standard_materials.add(StandardMaterial { material: atlas.water_material.clone(),
base_color: Color::AQUAMARINE.with_a(0.5),
alpha_mode: AlphaMode::Blend,
..default()
}),
..default() ..default()
},)); },));
} }

View File

@@ -1,11 +1,16 @@
use bevy::asset::Handle; use bevy::asset::Handle;
use bevy::pbr::ExtendedMaterial;
use bevy::prelude::*; use bevy::prelude::*;
use bevy::prelude::{Component, Image, Resource}; use bevy::prelude::{Component, Image, Resource};
use bevy::reflect::Reflect; use bevy::reflect::Reflect;
use crate::shader_extensions::chunk_material::ChunkMaterial;
#[derive(Resource)] #[derive(Resource)]
pub struct ChunkAtlas { pub struct ChunkAtlas {
pub handle: Handle<Image>, pub handle: Handle<Image>,
pub chunk_material_handle: Handle<ExtendedMaterial<StandardMaterial, ChunkMaterial>>,
pub water_material: Handle<StandardMaterial>,
pub is_loaded: bool, pub is_loaded: bool,
} }