From 3884f9bdd775afd3a40503286eb5d06ef72eeb1a Mon Sep 17 00:00:00 2001 From: HampusM Date: Sat, 18 May 2024 23:35:41 +0200 Subject: fix(engine): prevent camera moving when window regains focus --- engine/src/camera/fly.rs | 8 ++--- engine/src/input.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 81 insertions(+), 12 deletions(-) diff --git a/engine/src/camera/fly.rs b/engine/src/camera/fly.rs index 3f5a0c2..ed41253 100644 --- a/engine/src/camera/fly.rs +++ b/engine/src/camera/fly.rs @@ -7,7 +7,7 @@ use glfw::window::{Key, KeyState}; use crate::camera::Camera; use crate::delta_time::DeltaTime; use crate::event::Update as UpdateEvent; -use crate::input::{Cursor, Keys}; +use crate::input::{Cursor, CursorFlags, Keys}; use crate::vector::{Vec2, Vec3}; /// Fly camera extension. @@ -41,6 +41,7 @@ fn update( camera_query: Query<(Camera,)>, keys: Single, cursor: Single, + cursor_flags: Single, delta_time: Single, mut cursor_state: Local, options: Local, @@ -53,11 +54,10 @@ fn update( return; }; - if cursor.has_moved && cursor_state.first_mouse { + if cursor.has_moved && cursor_flags.is_first_move.flag { println!("First cursor move"); cursor_state.last_pos = cursor.position; - cursor_state.first_mouse = false; } let delta_time = delta_time.duration; @@ -119,7 +119,6 @@ struct CursorState last_pos: Vec2, current_pitch: f64, current_yaw: f64, - first_mouse: bool, } impl Default for CursorState @@ -130,7 +129,6 @@ impl Default for CursorState last_pos: Vec2::default(), current_pitch: 0.0, current_yaw: 0.0, - first_mouse: true, } } } diff --git a/engine/src/input.rs b/engine/src/input.rs index f64d93e..7bd664f 100644 --- a/engine/src/input.rs +++ b/engine/src/input.rs @@ -4,7 +4,7 @@ use ecs::extension::Collector as ExtensionCollector; use ecs::sole::Single; use ecs::Sole; -use crate::event::Start as StartEvent; +use crate::event::{PreUpdate as PreUpdateEvent, Start as StartEvent}; use crate::vector::Vec2; use crate::window::{Key, KeyState, Window}; @@ -49,19 +49,48 @@ impl Keys } } -#[derive(Debug, Clone, Default, Sole)] +#[derive(Debug, Default, Clone, Sole)] pub struct Cursor { pub position: Vec2, pub has_moved: bool, } -impl Cursor +#[derive(Debug, Clone, Sole)] +pub struct CursorFlags { - #[must_use] - pub fn new() -> Self + /// This flag is set in two situations: + /// A: The window has just started + /// B: The window has gained focus again after losing focus. + /// + /// This flag only lasts a single tick then it is cleared (at the beginning of the + /// next tick). + pub is_first_move: CursorFlag, +} + +impl Default for CursorFlags +{ + fn default() -> Self { - Self::default() + Self { + is_first_move: CursorFlag { flag: true, ..Default::default() }, + } + } +} + +#[derive(Debug, Default, Clone)] +pub struct CursorFlag +{ + pub flag: bool, + pub pending_clear: bool, +} + +impl CursorFlag +{ + pub fn clear(&mut self) + { + self.flag = false; + self.pending_clear = false; } } @@ -74,13 +103,20 @@ impl ecs::extension::Extension for Extension fn collect(self, mut collector: ExtensionCollector<'_>) { collector.add_system(StartEvent, initialize); + collector.add_system(PreUpdateEvent, maybe_clear_cursor_is_first_move); collector.add_sole(Keys::default()).ok(); collector.add_sole(Cursor::default()).ok(); + collector.add_sole(CursorFlags::default()).ok(); } } -fn initialize(keys: Single, cursor: Single, window: Single) +fn initialize( + keys: Single, + cursor: Single, + cursor_flags: Single, + window: Single, +) { let keys_weak_ref = keys.to_weak_ref(); @@ -110,4 +146,39 @@ fn initialize(keys: Single, cursor: Single, window: Single cursor.has_moved = true; }); + + let cursor_flags_weak_ref = cursor_flags.to_weak_ref(); + + window.set_focus_callback(move |is_focused| { + #[cfg(feature = "debug")] + tracing::trace!("Window is focused: {is_focused}"); + + let cursor_flags_ref = cursor_flags_weak_ref.access().expect("No world"); + + cursor_flags_ref.to_single().is_first_move.flag = is_focused; + }); +} + +fn maybe_clear_cursor_is_first_move( + cursor: Single, + mut cursor_flags: Single, +) +{ + if cursor_flags.is_first_move.pending_clear { + #[cfg(feature = "debug")] + tracing::trace!("Clearing is_first_move"); + + // This flag was set for the whole previous tick so it can be cleared now + cursor_flags.is_first_move.clear(); + + return; + } + + if cursor.has_moved && cursor_flags.is_first_move.flag { + #[cfg(feature = "debug")] + tracing::trace!("Setting flag to clear is_first_move next tick"); + + // Make this system clear is_first_move the next time it runs + cursor_flags.is_first_move.pending_clear = true; + } } -- cgit v1.2.3-18-g5258