fixes to camera orbit
This commit is contained in:
@@ -141,6 +141,14 @@ impl Map {
|
||||
return Vec3::new(w / 2., self.sealevel, h / 2.);
|
||||
}
|
||||
|
||||
pub fn get_center_with_height(&self) -> Vec3 {
|
||||
let w = self.get_world_width();
|
||||
let h = self.get_world_height();
|
||||
let mut pos = Vec3::new(w / 2., self.sealevel, h / 2.);
|
||||
pos.y = self.sample_height(&HexCoord::from_world_pos(pos));
|
||||
return pos;
|
||||
}
|
||||
|
||||
pub fn get_world_width(&self) -> f32 {
|
||||
return (self.width * Chunk::SIZE) as f32 * SHORT_DIAGONAL;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use bevy::math::IVec2;
|
||||
|
||||
use crate::hex_utils::HexCoord;
|
||||
|
||||
use super::chunk::Chunk;
|
||||
@@ -42,4 +46,40 @@ impl MeshChunkData {
|
||||
}
|
||||
return (data, has_land);
|
||||
}
|
||||
|
||||
pub fn caluclate_water_distances(data: &mut Vec<MeshChunkData>, height: usize, width: usize, range: usize) {
|
||||
let mut open: VecDeque<(HexCoord, f32, usize)> = VecDeque::new();
|
||||
let mut closed: Vec<(HexCoord, f32)> = Vec::new();
|
||||
for z in 0..height {
|
||||
for x in 0..width {
|
||||
let chunk = &mut data[z * height + x];
|
||||
chunk.prepare_chunk_open(x * Chunk::SIZE, z * Chunk::SIZE, &mut open);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn prepare_chunk_open(&mut self, offset_x: usize, offset_z: usize, open: &mut VecDeque<(HexCoord, f32, usize)>) {
|
||||
for z in 0..Chunk::SIZE {
|
||||
for x in 0..Chunk::SIZE {
|
||||
let coord = HexCoord::from_grid_pos(x + offset_x, z + offset_z);
|
||||
let idx = coord.to_chunk_local_index();
|
||||
let h = self.heights[idx];
|
||||
self.distance_to_land[idx] = if h > self.sealevel { 0.0 } else { 4.0 };
|
||||
if h > self.sealevel {
|
||||
open.push_back((coord, h, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fill_chunk_borders(
|
||||
&mut self,
|
||||
chunks: &Vec<MeshChunkData>,
|
||||
offset: IVec2,
|
||||
open: &mut VecDeque<(HexCoord, f32, usize)>,
|
||||
closed: &mut Vec<(HexCoord, f32)>,
|
||||
) {
|
||||
self.prepare_chunk_open(offset.x as usize * Chunk::SIZE, offset.y as usize * Chunk::SIZE, open);
|
||||
todo!("Fill closed list with bordering tiles")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ use bevy::core_pipeline::experimental::taa::{TemporalAntiAliasBundle, TemporalAn
|
||||
use bevy::core_pipeline::prepass::DepthPrepass;
|
||||
use bevy::input::mouse::{MouseMotion, MouseScrollUnit, MouseWheel};
|
||||
use bevy::prelude::*;
|
||||
use bevy::window::CursorGrabMode;
|
||||
use shared::states::MenuState;
|
||||
use shared::sets::GameplaySet;
|
||||
use shared::tags::MainCamera;
|
||||
use world_generation::hex_utils::HexCoord;
|
||||
use world_generation::prelude::Map;
|
||||
use world_generation::states::GeneratorState;
|
||||
|
||||
use super::components::*;
|
||||
|
||||
@@ -15,11 +15,15 @@ pub struct PhosCameraPlugin;
|
||||
impl Plugin for PhosCameraPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
app.register_type::<PhosCamera>();
|
||||
app.register_type::<PhosOrbitCamera>();
|
||||
|
||||
app.add_systems(PreStartup, setup);
|
||||
|
||||
app.add_systems(Update, rts_camera_system.run_if(in_state(MenuState::InGame)));
|
||||
app.add_systems(PostUpdate, limit_camera_bounds.run_if(in_state(MenuState::InGame)));
|
||||
// app.add_systems(Update, rts_camera_system.in_set(GameplaySet));
|
||||
// app.add_systems(PostUpdate, limit_camera_bounds.in_set(GameplaySet));
|
||||
app.add_systems(Update, orbit_camera_upate.in_set(GameplaySet));
|
||||
|
||||
app.add_systems(Update, init_bounds.run_if(in_state(GeneratorState::SpawnMap)));
|
||||
//Free Cam
|
||||
//app.add_systems(Update, (grab_mouse, (update_camera, update_camera_mouse).chain()));
|
||||
|
||||
@@ -27,6 +31,22 @@ impl Plugin for PhosCameraPlugin {
|
||||
}
|
||||
}
|
||||
|
||||
fn init_bounds(
|
||||
mut commands: Commands,
|
||||
mut cam: Query<(&mut Transform, Entity), With<PhosCamera>>,
|
||||
heightmap: Res<Map>,
|
||||
) {
|
||||
let (mut cam_t, cam_entity) = cam.single_mut();
|
||||
cam_t.translation = heightmap.get_center();
|
||||
commands
|
||||
.entity(cam_entity)
|
||||
.insert(CameraBounds::from_size(heightmap.get_world_size()))
|
||||
.insert(PhosOrbitCamera {
|
||||
target: heightmap.get_center_with_height(),
|
||||
..Default::default()
|
||||
});
|
||||
}
|
||||
|
||||
fn setup(mut commands: Commands, mut msaa: ResMut<Msaa>) {
|
||||
commands
|
||||
.spawn((
|
||||
@@ -37,93 +57,108 @@ fn setup(mut commands: Commands, mut msaa: ResMut<Msaa>) {
|
||||
PhosCamera::default(),
|
||||
MainCamera,
|
||||
DepthPrepass,
|
||||
PhosCameraTargets::default(),
|
||||
PhosOrbitCamera::default(),
|
||||
))
|
||||
.insert(TemporalAntiAliasBundle::default());
|
||||
|
||||
*msaa = Msaa::Off;
|
||||
}
|
||||
fn update_camera(
|
||||
mut cam_query: Query<(&PhosCamera, &mut Transform)>,
|
||||
keyboard_input: Res<ButtonInput<KeyCode>>,
|
||||
|
||||
fn orbit_camera_upate(
|
||||
mut cam_query: Query<(&mut Transform, &PhosCamera, &mut PhosOrbitCamera, &CameraBounds)>,
|
||||
mut wheel: EventReader<MouseWheel>,
|
||||
mut mouse_motion: EventReader<MouseMotion>,
|
||||
mouse: Res<ButtonInput<MouseButton>>,
|
||||
key: Res<ButtonInput<KeyCode>>,
|
||||
time: Res<Time>,
|
||||
windows: Query<&Window>,
|
||||
map: Res<Map>,
|
||||
#[cfg(debug_assertions)] mut gizmos: Gizmos,
|
||||
) {
|
||||
let window = windows.single();
|
||||
if window.cursor.grab_mode != CursorGrabMode::Locked {
|
||||
return;
|
||||
}
|
||||
let (cam, mut transform) = cam_query.single_mut();
|
||||
let (mut transform, config, mut orbit, bounds) = cam_query.single_mut();
|
||||
|
||||
let mut move_vec = Vec3::ZERO;
|
||||
if keyboard_input.pressed(KeyCode::KeyA) {
|
||||
move_vec += Vec3::NEG_X;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyD) {
|
||||
move_vec += Vec3::X;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyW) {
|
||||
move_vec += Vec3::NEG_Z;
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::KeyS) {
|
||||
move_vec += Vec3::Z;
|
||||
}
|
||||
let target = orbit.target;
|
||||
let mut cam_pos = target;
|
||||
|
||||
let rot = transform.rotation;
|
||||
move_vec = (rot * move_vec.normalize_or_zero()) * cam.speed * time.delta_seconds();
|
||||
//Apply Camera Dist
|
||||
cam_pos -= orbit.forward * orbit.distance;
|
||||
|
||||
if keyboard_input.pressed(KeyCode::ShiftLeft) {
|
||||
move_vec += Vec3::from(transform.down());
|
||||
}
|
||||
if keyboard_input.pressed(KeyCode::Space) {
|
||||
move_vec += Vec3::from(transform.up());
|
||||
}
|
||||
|
||||
transform.translation += move_vec.normalize_or_zero() * cam.speed * time.delta_seconds();
|
||||
}
|
||||
|
||||
fn update_camera_mouse(
|
||||
mut cam_query: Query<&mut Transform, With<PhosCamera>>,
|
||||
mut mouse_move: EventReader<MouseMotion>,
|
||||
time: Res<Time>,
|
||||
windows: Query<&Window>,
|
||||
) {
|
||||
let window = windows.single();
|
||||
if window.cursor.grab_mode != CursorGrabMode::Locked {
|
||||
return;
|
||||
}
|
||||
let mut transform = cam_query.single_mut();
|
||||
|
||||
for ev in mouse_move.read() {
|
||||
let (mut yaw, mut pitch, _) = transform.rotation.to_euler(EulerRot::YXZ);
|
||||
match window.cursor.grab_mode {
|
||||
CursorGrabMode::None => (),
|
||||
_ => {
|
||||
// Using smallest of height or width ensures equal vertical and horizontal sensitivity
|
||||
pitch -= ev.delta.y.to_radians() * time.delta_seconds() * 5.;
|
||||
yaw -= ev.delta.x.to_radians() * time.delta_seconds() * 5.;
|
||||
}
|
||||
if mouse.pressed(MouseButton::Middle) {
|
||||
let mut orbit_move = Vec2::ZERO;
|
||||
for e in mouse_motion.read() {
|
||||
orbit_move += e.delta;
|
||||
}
|
||||
|
||||
pitch = pitch.clamp(-1.54, 1.54);
|
||||
|
||||
// Order is important to prevent unintended roll
|
||||
transform.rotation = Quat::from_axis_angle(Vec3::Y, yaw) * Quat::from_axis_angle(Vec3::X, pitch);
|
||||
orbit_move *= f32::to_radians(config.speed) * time.delta_seconds();
|
||||
let rot_y = Quat::from_axis_angle(Vec3::Y, orbit_move.x);
|
||||
let right = orbit.forward.cross(Vec3::Y).normalize();
|
||||
let rot_x = Quat::from_axis_angle(right, orbit_move.y);
|
||||
orbit.forward = rot_x * rot_y * orbit.forward;
|
||||
orbit.forward.y = orbit.forward.y.clamp(-1.0, 0.0);
|
||||
orbit.forward = orbit.forward.normalize();
|
||||
}
|
||||
}
|
||||
|
||||
fn grab_mouse(mut windows: Query<&mut Window>, mouse: Res<ButtonInput<MouseButton>>, key: Res<ButtonInput<KeyCode>>) {
|
||||
let mut window = windows.single_mut();
|
||||
|
||||
if mouse.just_pressed(MouseButton::Middle) {
|
||||
window.cursor.visible = false;
|
||||
window.cursor.grab_mode = CursorGrabMode::Locked;
|
||||
if key.pressed(KeyCode::KeyE) {
|
||||
let rot = Quat::from_axis_angle(Vec3::Y, f32::to_radians(config.speed) * time.delta_seconds());
|
||||
orbit.forward = rot * orbit.forward;
|
||||
} else if key.pressed(KeyCode::KeyQ) {
|
||||
let rot = Quat::from_axis_angle(Vec3::Y, f32::to_radians(-config.speed) * time.delta_seconds());
|
||||
orbit.forward = rot * orbit.forward;
|
||||
}
|
||||
|
||||
if key.just_pressed(KeyCode::Escape) {
|
||||
window.cursor.visible = true;
|
||||
window.cursor.grab_mode = CursorGrabMode::None;
|
||||
let mut cam_move = Vec3::ZERO;
|
||||
|
||||
if key.pressed(KeyCode::KeyA) {
|
||||
cam_move.x = 1.;
|
||||
} else if key.pressed(KeyCode::KeyD) {
|
||||
cam_move.x = -1.;
|
||||
}
|
||||
|
||||
if key.pressed(KeyCode::KeyW) {
|
||||
cam_move.z = 1.;
|
||||
} else if key.pressed(KeyCode::KeyS) {
|
||||
cam_move.z = -1.;
|
||||
}
|
||||
|
||||
if key.pressed(KeyCode::ShiftLeft) {
|
||||
cam_move *= 2.0;
|
||||
}
|
||||
|
||||
if cam_move != Vec3::ZERO {
|
||||
cam_move = cam_move.normalize();
|
||||
let move_fwd = Vec3::new(orbit.forward.x, 0., orbit.forward.z).normalize();
|
||||
let move_rot = Quat::from_rotation_arc(Vec3::NEG_Z, move_fwd);
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
gizmos.arrow(orbit.target, orbit.target + move_fwd, LinearRgba::WHITE.with_alpha(0.5));
|
||||
gizmos.arrow(orbit.target, orbit.target - (move_rot * cam_move), LinearRgba::BLUE);
|
||||
}
|
||||
orbit.target -= (move_rot * cam_move) * config.speed * time.delta_seconds();
|
||||
orbit.target.y = sample_ground(orbit.target, &map);
|
||||
|
||||
orbit.target.x = orbit.target.x.clamp(bounds.min.x, bounds.max.x);
|
||||
orbit.target.z = orbit.target.z.clamp(bounds.min.y, bounds.max.y);
|
||||
}
|
||||
|
||||
let mut scroll = 0.0;
|
||||
for e in wheel.read() {
|
||||
match e.unit {
|
||||
MouseScrollUnit::Line => scroll += e.y * 5.,
|
||||
MouseScrollUnit::Pixel => scroll += e.y,
|
||||
}
|
||||
}
|
||||
|
||||
orbit.distance -= scroll * time.delta_seconds() * config.zoom_speed;
|
||||
orbit.distance = orbit.distance.clamp(config.min_height, config.max_height);
|
||||
|
||||
// let ground_below_cam = sample_ground(cam_pos, &map) + config.min_height;
|
||||
// if cam_pos.y <= ground_below_cam {
|
||||
// cam_pos.y = ground_below_cam;
|
||||
// }
|
||||
|
||||
// if cam_pos.y < target.y {
|
||||
// cam_pos.y = target.y;
|
||||
// }
|
||||
|
||||
transform.translation = cam_pos;
|
||||
transform.look_at(target, Vec3::Y);
|
||||
}
|
||||
|
||||
fn rts_camera_system(
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use bevy::prelude::*;
|
||||
use bevy::{math::Direction3d, prelude::*};
|
||||
use rayon::str;
|
||||
use world_generation::{hex_utils::SHORT_DIAGONAL, prelude::Chunk};
|
||||
|
||||
#[derive(Component, Reflect)]
|
||||
@@ -18,12 +19,28 @@ impl Default for PhosCamera {
|
||||
min_height: 10.,
|
||||
max_height: 420.,
|
||||
speed: 100.,
|
||||
zoom_speed: 0.3,
|
||||
zoom_speed: 20.,
|
||||
min_angle: (20. as f32).to_radians(),
|
||||
max_angle: 1.,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Component, Reflect)]
|
||||
pub struct PhosOrbitCamera {
|
||||
pub target: Vec3,
|
||||
pub distance: f32,
|
||||
pub forward: Vec3,
|
||||
}
|
||||
|
||||
impl Default for PhosOrbitCamera {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
target: Default::default(),
|
||||
distance: 40.0,
|
||||
forward: Vec3::new(0.0, -0.5, 0.5).normalize(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct PhosCameraTargets {
|
||||
@@ -53,14 +70,11 @@ pub struct CameraBounds {
|
||||
}
|
||||
|
||||
impl CameraBounds {
|
||||
pub fn from_size(size: UVec2) -> Self {
|
||||
pub fn from_size(world_size: Vec2) -> Self {
|
||||
let padding = Chunk::WORLD_SIZE;
|
||||
return Self {
|
||||
min: Vec2::ZERO - padding,
|
||||
max: Vec2::new(
|
||||
(size.x as usize * Chunk::SIZE) as f32 * SHORT_DIAGONAL,
|
||||
(size.y * Chunk::SIZE as u32) as f32 * 1.5,
|
||||
) + padding,
|
||||
max: world_size + padding,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ use world_generation::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
camera_system::components::*,
|
||||
prelude::{PhosAssets, PhosChunk, PhosChunkRegistry},
|
||||
shader_extensions::{
|
||||
chunk_material::ChunkMaterial,
|
||||
@@ -144,7 +143,6 @@ fn finalize_texture(
|
||||
|
||||
fn create_heightmap(
|
||||
mut commands: Commands,
|
||||
mut cam: Query<(&mut Transform, Entity), With<PhosCamera>>,
|
||||
mut next_state: ResMut<NextState<GeneratorState>>,
|
||||
biome_painter: Res<BiomePainter>,
|
||||
) {
|
||||
@@ -200,10 +198,6 @@ fn create_heightmap(
|
||||
};
|
||||
let (heightmap, biome_map) = generate_heightmap(&config, 42069, &biome_painter);
|
||||
|
||||
let (mut cam_t, cam_entity) = cam.single_mut();
|
||||
cam_t.translation = heightmap.get_center();
|
||||
|
||||
commands.entity(cam_entity).insert(CameraBounds::from_size(config.size));
|
||||
commands.insert_resource(heightmap);
|
||||
commands.insert_resource(biome_map);
|
||||
commands.insert_resource(config);
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use bevy::{gizmos::gizmos, prelude::*};
|
||||
use shared::resources::TileUnderCursor;
|
||||
use shared::states::GameplayState;
|
||||
use shared::{resources::TileUnderCursor, sets::GameplaySet};
|
||||
use world_generation::{
|
||||
consts::{HEX_CORNERS, WATER_HEX_CORNERS},
|
||||
prelude::Map,
|
||||
states::GeneratorState,
|
||||
};
|
||||
|
||||
use crate::camera_system::components::{PhosCamera, PhosOrbitCamera};
|
||||
|
||||
pub struct DebugPlugin;
|
||||
|
||||
impl Plugin for DebugPlugin {
|
||||
@@ -27,6 +29,7 @@ impl Plugin for DebugPlugin {
|
||||
.run_if(in_state(DebugState::Verbose)),
|
||||
);
|
||||
|
||||
app.add_systems(Update, camera_debug.in_set(GameplaySet));
|
||||
app.add_systems(Update, regenerate_map.run_if(in_state(GeneratorState::Idle)));
|
||||
|
||||
app.insert_resource(Shape(Polyline3d::new([
|
||||
@@ -89,4 +92,14 @@ fn show_water_corners(pos: Vec3, gizmos: &mut Gizmos) {
|
||||
}
|
||||
}
|
||||
|
||||
fn camera_debug(mut cam_query: Query<(&PhosCamera, &PhosOrbitCamera)>, mut gizmos: Gizmos) {
|
||||
let (config, orbit) = cam_query.single();
|
||||
|
||||
gizmos.sphere(orbit.target, Quat::IDENTITY, 0.3, LinearRgba::RED);
|
||||
let cam_proxy = orbit.target - (orbit.forward * 10.0);
|
||||
gizmos.ray(orbit.target, orbit.forward * 10.0, LinearRgba::rgb(1.0, 0.0, 1.0));
|
||||
|
||||
gizmos.circle(cam_proxy, Dir3::Y, 0.3, LinearRgba::rgb(1.0, 1.0, 0.0));
|
||||
}
|
||||
|
||||
fn verbose_data() {}
|
||||
|
||||
Reference in New Issue
Block a user