diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..a55e7a1 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/engine/world_generation/src/heightmap.rs b/engine/world_generation/src/heightmap.rs index 0676b16..9b0d792 100644 --- a/engine/world_generation/src/heightmap.rs +++ b/engine/world_generation/src/heightmap.rs @@ -6,30 +6,24 @@ pub fn generate_heightmap(height: usize, width: usize, cfg: &GenerationConfig, s let mut chunks: Vec = Vec::with_capacity(height * width); for z in 0..height { for x in 0..width { - chunks.push(generate_chunk(x as f64, z as f64, 32, cfg, seed)); + chunks.push(generate_chunk(x as f64, z as f64, cfg, seed)); } } return Map { - chunks: chunks, - height: height, - width: width, + chunks, + height, + width, }; } -pub fn generate_chunk( - chunk_x: f64, - chunk_z: f64, - size: usize, - cfg: &GenerationConfig, - seed: u32, -) -> Chunk { - let mut result: Vec = Vec::with_capacity(size * size); +pub fn generate_chunk(chunk_x: f64, chunk_z: f64, cfg: &GenerationConfig, seed: u32) -> Chunk { + let mut result: Vec = Vec::with_capacity(Chunk::SIZE * Chunk::SIZE); let noise = SuperSimplex::new(seed); - for z in 0..size { - for x in 0..size { + for z in 0..Chunk::SIZE { + for x in 0..Chunk::SIZE { result.push(sample_point( - x as f64 + chunk_x * size as f64, - z as f64 + chunk_z * size as f64, + x as f64 + chunk_x * Chunk::SIZE as f64, + z as f64 + chunk_z * Chunk::SIZE as f64, &cfg, &noise, )); @@ -37,7 +31,6 @@ pub fn generate_chunk( } return Chunk { points: result, - size: size, chunk_offset: IVec2::new(chunk_x as i32, chunk_z as i32), }; } diff --git a/engine/world_generation/src/hex_utils.rs b/engine/world_generation/src/hex_utils.rs index 0e8a09d..13e01a5 100644 --- a/engine/world_generation/src/hex_utils.rs +++ b/engine/world_generation/src/hex_utils.rs @@ -1,9 +1,162 @@ +use crate::prelude::Chunk; use bevy::prelude::*; pub const OUTER_RADIUS: f32 = 1.; pub const INNER_RADIUS: f32 = OUTER_RADIUS * 0.866025404; -pub fn to_hex_pos(pos: Vec3) -> Vec3 { - let x = (pos.x + pos.z * 0.5 - (pos.z / 2.).floor()) * (INNER_RADIUS * 2.); - return Vec3::new(x, pos.y, pos.z * OUTER_RADIUS * 1.5); +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) -> Vec3 { + let x = (offset.x as f32 + offset.y as f32 * 0.5 - (offset.y as f32 / 2.).floor()) + * (INNER_RADIUS * 2.); + return Vec3::new(x, 0., offset.y as f32 * OUTER_RADIUS * 1.5); +} + +pub fn offset_to_hex(offset: IVec2) -> IVec3 { + return IVec3 { + x: offset.x, + y: offset.y, + z: -offset.x - offset.y, + }; +} + +pub fn snap_to_hex_grid(world_pos: Vec3) -> Vec3 { + return offset_to_world(world_to_offset_pos(world_pos)); +} + +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: i32) -> f32 { + return dist as f32 * (2. * INNER_RADIUS); +} + +pub fn get_tile_count(radius: i32)->i32{ + return 1 + 3 * (radius + 1) * radius; +} + +#[derive(Default, Clone, Copy)] +pub struct HexCoord { + pub hex: IVec3, + pub offset: IVec2, + pub world: Vec3, +} + +impl PartialEq for HexCoord { + fn eq(&self, other: &Self) -> bool { + return self.offset == other.offset; + } +} + +impl Eq for HexCoord {} + +impl HexCoord { + pub const DIRECTIONS: [IVec3; 6] = [ + IVec3::new(1, -1, 0), + IVec3::new(1, 0, -1), + IVec3::new(0, 1, -1), + IVec3::new(-1, 1, 0), + IVec3::new(-1, 0, 1), + IVec3::new(0, -1, 1), + ]; + + pub const ZERO: HexCoord = HexCoord { + offset: IVec2::ZERO, + hex: IVec3::ZERO, + world: Vec3::ZERO, + }; + + pub fn new(x: i32, z: i32) -> Self { + return Self::from_offset(IVec2::new(x, z)); + } + pub fn from_grid_pos(x: usize, z: usize) -> Self { + return HexCoord::new(x as i32, z as i32); + } + pub fn from_offset(offset_pos: IVec2) -> Self { + return HexCoord { + offset: offset_pos, + hex: offset_to_hex(offset_pos), + world: offset3d_to_world(offset_pos.extend(0).xzy().as_vec3()), + }; + } + + pub fn to_chunk_pos(&self) -> IVec2 { + return IVec2 { + x: (self.offset.x as f32 / Chunk::SIZE as f32).floor() as i32, + y: (self.offset.y as f32 / Chunk::SIZE as f32).floor() as i32, + }; + } + + pub fn to_chunk_index(&self, width: usize) -> usize { + let pos = self.to_chunk_pos(); + return pos.x as usize + pos.y as usize * width; + } + + 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_offset(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: i32)-> HexCoord{ + let s = Self::DIRECTIONS[dir % 6] * radius; + return Self::from_offset(self.hex.xy() + s.xy()); + } + + pub fn get_neighbor(&self, dir: i32)-> HexCoord{ + let d = Self::DIRECTIONS[dir % 6]; + return Self::from_offset(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), + ] + } } diff --git a/engine/world_generation/src/lib.rs b/engine/world_generation/src/lib.rs index 134f288..e4c6c42 100644 --- a/engine/world_generation/src/lib.rs +++ b/engine/world_generation/src/lib.rs @@ -20,9 +20,12 @@ pub mod prelude { } pub struct Chunk { pub points: Vec, - pub size: usize, pub chunk_offset: IVec2, } + + impl Chunk { + pub const SIZE: usize = 32; + } pub struct Map { pub chunks: Vec, pub height: usize, diff --git a/engine/world_generation/src/mesh_generator.rs b/engine/world_generation/src/mesh_generator.rs index e04f619..1c275df 100644 --- a/engine/world_generation/src/mesh_generator.rs +++ b/engine/world_generation/src/mesh_generator.rs @@ -1,5 +1,5 @@ use crate::{ - hex_utils::{to_hex_pos, INNER_RADIUS, OUTER_RADIUS}, + hex_utils::{offset3d_to_world, INNER_RADIUS, OUTER_RADIUS}, prelude::*, }; use bevy::{ @@ -20,17 +20,17 @@ const HEX_CORNERS: [Vec3; 6] = [ ]; pub fn generate_chunk_mesh(chunk: &Chunk) -> Mesh { - let vertex_count: usize = chunk.size * chunk.size; + let vertex_count: usize = Chunk::SIZE * Chunk::SIZE; let mut verts = Vec::with_capacity(vertex_count); let mut uvs = Vec::with_capacity(vertex_count); let mut normals = Vec::with_capacity(vertex_count); let mut indices = Vec::with_capacity(vertex_count); - for z in 0..chunk.size { - for x in 0..chunk.size { - let height = chunk.points[x + z * chunk.size]; + for z in 0..Chunk::SIZE { + for x in 0..Chunk::SIZE { + let height = chunk.points[x + z * Chunk::SIZE]; let off_pos = Vec3::new(x as f32, height, z as f32); - let grid_pos = to_hex_pos(off_pos); + let grid_pos = offset3d_to_world(off_pos); create_tile(grid_pos, &mut verts, &mut uvs, &mut normals, &mut indices); } } diff --git a/game/camera_system/src/lib.rs b/game/camera_system/src/lib.rs index 0a9c980..15ffe97 100644 --- a/game/camera_system/src/lib.rs +++ b/game/camera_system/src/lib.rs @@ -19,7 +19,7 @@ pub struct PhosCameraPlugin; impl Plugin for PhosCameraPlugin { fn build(&self, app: &mut App) { app.add_systems(Startup, setup) - .add_systems(Update, (update_camera, grab_mouse)); + .add_systems(Update, (update_camera, grab_mouse, update_camera_mouse)); } } @@ -84,14 +84,15 @@ fn update_camera_mouse( let (mut pitch, mut yaw, _) = transform.rotation.to_euler(EulerRot::XYZ); - pitch -= cam_rot.y.to_radians() ; - yaw -= cam_rot.x.to_radians() ; + pitch -= cam_rot.y.to_radians(); + yaw -= cam_rot.x.to_radians(); pitch = pitch.clamp(-1.54, 1.54); // if rot_x > PI && cam_rot.x < 2. * PI { // rot_x = PI; // } - transform.rotation = Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch); + transform.rotation = + Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch); } fn grab_mouse( diff --git a/game/main/src/phos.rs b/game/main/src/phos.rs index 0694660..e76b494 100644 --- a/game/main/src/phos.rs +++ b/game/main/src/phos.rs @@ -1,10 +1,12 @@ use bevy::{pbr::CascadeShadowConfig, prelude::*}; use camera_system::PhosCameraPlugin; use iyes_perf_ui::prelude::*; +use world_generation::hex_utils::offset_to_world; use world_generation::{ - heightmap::generate_heightmap, hex_utils::to_hex_pos, mesh_generator::generate_chunk_mesh, - prelude::*, + heightmap::generate_heightmap, hex_utils::offset3d_to_world, + mesh_generator::generate_chunk_mesh, prelude::*, }; + pub struct PhosGamePlugin; impl Plugin for PhosGamePlugin { @@ -74,10 +76,7 @@ fn create_map( for chunk in heightmap.chunks { let mesh = generate_chunk_mesh(&chunk); - let pos = to_hex_pos( - Vec3::new(chunk.chunk_offset.x as f32, 0., chunk.chunk_offset.y as f32) - * chunk.size as f32, - ); + let pos = offset_to_world(chunk.chunk_offset * Chunk::SIZE as i32); commands.spawn(PbrBundle { mesh: meshes.add(mesh), material: debug_material.clone(),