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/input.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 7 deletions(-) (limited to 'engine/src/input.rs') 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