summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-05-18 23:35:41 +0200
committerHampusM <hampus@hampusmat.com>2024-05-18 23:35:41 +0200
commit3884f9bdd775afd3a40503286eb5d06ef72eeb1a (patch)
treeed8b5a39fbf485a71be31ba6fd30bef58dea34f6
parentbcf1e9c00e3959c3db047d2d8b3ac7d6c4853796 (diff)
fix(engine): prevent camera moving when window regains focus
-rw-r--r--engine/src/camera/fly.rs8
-rw-r--r--engine/src/input.rs85
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<Keys>,
cursor: Single<Cursor>,
+ cursor_flags: Single<CursorFlags>,
delta_time: Single<DeltaTime>,
mut cursor_state: Local<CursorState>,
options: Local<Options>,
@@ -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<f64>,
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<f64>,
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<Keys>, cursor: Single<Cursor>, window: Single<Window>)
+fn initialize(
+ keys: Single<Keys>,
+ cursor: Single<Cursor>,
+ cursor_flags: Single<CursorFlags>,
+ window: Single<Window>,
+)
{
let keys_weak_ref = keys.to_weak_ref();
@@ -110,4 +146,39 @@ fn initialize(keys: Single<Keys>, cursor: Single<Cursor>, window: Single<Window>
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<Cursor>,
+ mut cursor_flags: Single<CursorFlags>,
+)
+{
+ 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;
+ }
}