fixes to camera orbit

This commit is contained in:
2024-10-29 20:52:53 -04:00
parent 9120c70b80
commit 3e12fcadbc
6 changed files with 194 additions and 90 deletions

View File

@@ -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(

View File

@@ -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,
};
}
}

View File

@@ -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);

View File

@@ -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() {}