From cb05930d35134b269314e514f9a69ec3e40f279e Mon Sep 17 00:00:00 2001 From: HampusM Date: Tue, 20 Aug 2024 20:30:52 +0200 Subject: feat(engine): make fly camera more flexible --- engine/src/camera/fly.rs | 166 ++++++++++++++++++++++++++--------------------- 1 file changed, 92 insertions(+), 74 deletions(-) (limited to 'engine/src/camera') diff --git a/engine/src/camera/fly.rs b/engine/src/camera/fly.rs index 5b55cec..6bd5876 100644 --- a/engine/src/camera/fly.rs +++ b/engine/src/camera/fly.rs @@ -4,13 +4,54 @@ use ecs::system::{Into, System}; use ecs::{Component, Query}; use glfw::window::{Key, KeyState}; -use crate::camera::Camera; +use crate::camera::{Active as ActiveCamera, Camera}; use crate::delta_time::DeltaTime; use crate::event::Update as UpdateEvent; use crate::input::{Cursor, CursorFlags, Keys}; use crate::transform::Position; +use crate::util::builder; use crate::vector::{Vec2, Vec3}; +builder! { +/// A fly camera. +#[builder(name = Builder, derives = (Debug))] +#[derive(Debug, Component)] +#[non_exhaustive] +pub struct Fly { + pub current_pitch: f64, + pub current_yaw: f64, + pub speed: f32, +} +} + +impl Fly +{ + pub fn builder() -> Builder + { + Builder::default() + } +} + +impl Default for Fly +{ + fn default() -> Self + { + Self::builder().build() + } +} + +impl Default for Builder +{ + fn default() -> Self + { + Self { + current_yaw: -90.0, + current_pitch: 0.0, + speed: 3.0, + } + } +} + /// Fly camera extension. pub struct Extension(pub Options); @@ -20,13 +61,9 @@ impl ecs::extension::Extension for Extension { collector.add_system( UpdateEvent, - update.into_system().initialize(( - CursorState { - current_yaw: -90.0, - ..Default::default() - }, - self.0, - )), + update + .into_system() + .initialize((CursorState::default(), self.0)), ); } } @@ -34,12 +71,11 @@ impl ecs::extension::Extension for Extension #[derive(Debug, Component)] pub struct Options { - pub camera_speed: f32, pub mouse_sensitivity: f32, } fn update( - camera_query: Query<(Camera, Position)>, + camera_query: Query<(Camera, Position, Fly, ActiveCamera)>, keys: Single, cursor: Single, cursor_flags: Single, @@ -48,91 +84,73 @@ fn update( options: Local, ) { - let Some((mut camera, mut camera_pos)) = camera_query.iter().next() else { - #[cfg(feature = "debug")] - tracing::warn!("No camera"); + for (mut camera, mut camera_pos, mut fly_camera, _) in &camera_query { + if cursor.has_moved && cursor_flags.is_first_move.flag { + #[cfg(feature = "debug")] + tracing::debug!("First cursor move"); - return; - }; + cursor_state.last_pos = cursor.position; + } - if cursor.has_moved && cursor_flags.is_first_move.flag { - println!("First cursor move"); + let delta_time = delta_time.duration; - cursor_state.last_pos = cursor.position; - } - - let delta_time = delta_time.duration; + let mut x_offset = cursor.position.x - cursor_state.last_pos.x; + let mut y_offset = cursor_state.last_pos.y - cursor.position.y; - let mut x_offset = cursor.position.x - cursor_state.last_pos.x; - let mut y_offset = cursor_state.last_pos.y - cursor.position.y; + cursor_state.last_pos = cursor.position; - cursor_state.last_pos = cursor.position; + x_offset *= f64::from(options.mouse_sensitivity); + y_offset *= f64::from(options.mouse_sensitivity); - x_offset *= f64::from(options.mouse_sensitivity); - y_offset *= f64::from(options.mouse_sensitivity); + fly_camera.current_yaw += x_offset; + fly_camera.current_pitch += y_offset; - cursor_state.current_yaw += x_offset; - cursor_state.current_pitch += y_offset; + fly_camera.current_pitch = fly_camera.current_pitch.clamp(-89.0, 89.0); - cursor_state.current_pitch = cursor_state.current_pitch.clamp(-89.0, 89.0); + // TODO: This casting to a f32 from a f64 is horrible. fix it + #[allow(clippy::cast_possible_truncation)] + let direction = Vec3 { + x: (fly_camera.current_yaw.to_radians().cos() + * fly_camera.current_pitch.to_radians().cos()) as f32, + y: fly_camera.current_pitch.to_radians().sin() as f32, + z: (fly_camera.current_yaw.to_radians().sin() + * fly_camera.current_pitch.to_radians().cos()) as f32, + } + .normalize(); - // TODO: This casting to a f32 from a f64 is horrible. fix it - #[allow(clippy::cast_possible_truncation)] - let direction = Vec3 { - x: (cursor_state.current_yaw.to_radians().cos() - * cursor_state.current_pitch.to_radians().cos()) as f32, - y: cursor_state.current_pitch.to_radians().sin() as f32, - z: (cursor_state.current_yaw.to_radians().sin() - * cursor_state.current_pitch.to_radians().cos()) as f32, - } - .normalize(); + let cam_right = direction.cross(&Vec3::UP).normalize(); - let cam_right = direction.cross(&Vec3::UP).normalize(); + camera.global_up = cam_right.cross(&direction).normalize(); - camera.global_up = cam_right.cross(&direction).normalize(); + if matches!(keys.get_key_state(Key::W), KeyState::Pressed) { + camera_pos.position += + direction * fly_camera.speed * delta_time.as_secs_f32(); + } - if matches!(keys.get_key_state(Key::W), KeyState::Pressed) { - camera_pos.position += - direction * options.camera_speed * delta_time.as_secs_f32(); - } + if matches!(keys.get_key_state(Key::S), KeyState::Pressed) { + camera_pos.position -= + direction * fly_camera.speed * delta_time.as_secs_f32(); + } - if matches!(keys.get_key_state(Key::S), KeyState::Pressed) { - camera_pos.position -= - direction * options.camera_speed * delta_time.as_secs_f32(); - } + if matches!(keys.get_key_state(Key::A), KeyState::Pressed) { + let cam_left = -direction.cross(&Vec3::UP).normalize(); - if matches!(keys.get_key_state(Key::A), KeyState::Pressed) { - let cam_left = -direction.cross(&Vec3::UP).normalize(); + camera_pos.position += cam_left * fly_camera.speed * delta_time.as_secs_f32(); + } - camera_pos.position += cam_left * options.camera_speed * delta_time.as_secs_f32(); - } + if matches!(keys.get_key_state(Key::D), KeyState::Pressed) { + let cam_right = direction.cross(&Vec3::UP).normalize(); - if matches!(keys.get_key_state(Key::D), KeyState::Pressed) { - let cam_right = direction.cross(&Vec3::UP).normalize(); + camera_pos.position += + cam_right * fly_camera.speed * delta_time.as_secs_f32(); + } - camera_pos.position += - cam_right * options.camera_speed * delta_time.as_secs_f32(); + camera.target = camera_pos.position + direction; } - - camera.target = camera_pos.position + direction; } -#[derive(Debug, Component)] +#[derive(Debug, Default, Component)] struct CursorState { last_pos: Vec2, - current_pitch: f64, - current_yaw: f64, -} - -impl Default for CursorState -{ - fn default() -> Self - { - Self { - last_pos: Vec2::default(), - current_pitch: 0.0, - current_yaw: 0.0, - } - } } -- cgit v1.2.3-18-g5258