From 6698ace0c646fedcdda1a222272e601fded3f1df Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Mon, 23 Feb 2026 14:27:56 +0100 Subject: [PATCH] implement smooth camera --- include/camera.hpp | 14 +++++++++++--- include/config.hpp | 3 ++- src/camera.cpp | 45 +++++++++++++++++++++++++++++++-------------- src/main.cpp | 1 - 4 files changed, 44 insertions(+), 19 deletions(-) diff --git a/include/camera.hpp b/include/camera.hpp index 2c3666b..cc9e31a 100644 --- a/include/camera.hpp +++ b/include/camera.hpp @@ -11,19 +11,25 @@ class OrbitCamera3D { private: Camera camera; + + Vector3 position; Vector3 target; + Vector3 target_target; float distance; float angle_x; float angle_y; + + // Input Vector2 last_mouse; - bool dragging; + bool rotating; bool panning; bool target_lock; public: OrbitCamera3D() - : camera({0}), target(Vector3Zero()), distance(CAMERA_DISTANCE), - angle_x(0.0), angle_y(0.0), last_mouse(Vector2Zero()), dragging(false), + : camera({0}), position(Vector3Zero()), target(Vector3Zero()), + target_target(Vector3Zero()), distance(CAMERA_DISTANCE), angle_x(0.0), + angle_y(0.0), last_mouse(Vector2Zero()), rotating(false), panning(false), target_lock(true) { camera.position = Vector3(0, 0, -1.0 * distance); camera.target = target; @@ -35,6 +41,8 @@ public: ~OrbitCamera3D() {} public: + auto HandleCameraInput() -> Vector2; + auto Update(const Vector3 ¤t_target) -> void; }; diff --git a/include/config.hpp b/include/config.hpp index 46c4f6d..3f999eb 100644 --- a/include/config.hpp +++ b/include/config.hpp @@ -28,6 +28,7 @@ constexpr float ZOOM_MULTIPLIER = 4.0; constexpr float PAN_SPEED = 2.0; constexpr float PAN_MULTIPLIER = 10.0; constexpr float ROT_SPEED = 1.0; +constexpr float CAMERA_SMOOTH_SPEED = 15.0; // Physics Engine constexpr float SIM_SPEED = 4.0; // How large each update should be @@ -38,7 +39,7 @@ constexpr float DAMPENING_CONSTANT = 1.0; // Mass spring system constexpr float REST_LENGTH = 2.0; // Mass spring system constexpr float VERLET_DAMPENING = 0.05; // [0, 1] constexpr float BH_FORCE = 2.0; // BH: [1.0, 3.0] -constexpr float THETA = 1.0; // Barnes-Hut [0.5, ~] +constexpr float THETA = 1.0; // Barnes-Hut [0.5, 1.0] constexpr float SOFTENING = 0.01; // Barnes-Hut [0.01, 1.0] constexpr float GRID_FORCE = 0.02; // Grid: [0.0, ~0.05] constexpr float REPULSION_RANGE = 5.0 * REST_LENGTH; // Grid diff --git a/src/camera.cpp b/src/camera.cpp index c0673f2..b4629d9 100644 --- a/src/camera.cpp +++ b/src/camera.cpp @@ -1,20 +1,34 @@ #include "camera.hpp" +#include "config.hpp" +#include "util.hpp" -auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void { +#include +#include +#include + +auto OrbitCamera3D::HandleCameraInput() -> Vector2 { Vector2 mouse = GetMousePosition(); if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) { if (IsMouseButtonPressed(MOUSE_RIGHT_BUTTON)) { - dragging = true; + rotating = true; last_mouse = mouse; } else if (IsMouseButtonPressed(MOUSE_LEFT_BUTTON)) { panning = true; target_lock = false; last_mouse = mouse; } + + // Zoom + float wheel = GetMouseWheelMove(); + if (IsKeyDown(KEY_LEFT_SHIFT)) { + distance -= wheel * ZOOM_SPEED * ZOOM_MULTIPLIER; + } else { + distance -= wheel * ZOOM_SPEED; + } } if (IsMouseButtonReleased(MOUSE_RIGHT_BUTTON)) { - dragging = false; + rotating = false; } if (IsMouseButtonReleased(MOUSE_LEFT_BUTTON)) { panning = false; @@ -23,8 +37,13 @@ auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void { if (IsKeyPressed(KEY_L)) { target_lock = !target_lock; } + return mouse; +} - if (dragging) { +auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void { + Vector2 mouse = HandleCameraInput(); + + if (rotating) { Vector2 dx = Vector2Subtract(mouse, last_mouse); last_mouse = mouse; @@ -38,13 +57,15 @@ auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void { Vector2 dx = Vector2Subtract(mouse, last_mouse); last_mouse = mouse; - // float speed = PAN_SPEED; float speed; if (IsKeyDown(KEY_LEFT_SHIFT)) { speed = distance * PAN_SPEED / 1000.0 * PAN_MULTIPLIER; } else { speed = distance * PAN_SPEED / 1000.0; } + + // The panning needs to happen in camera coordinates, otherwise rotating the + // camera breaks it Vector3 forward = Vector3Normalize(Vector3Subtract(camera.target, camera.position)); Vector3 right = Vector3Normalize(Vector3CrossProduct(forward, camera.up)); @@ -57,17 +78,13 @@ auto OrbitCamera3D::Update(const Vector3 ¤t_target) -> void { } if (target_lock) { - target = current_target; + target_target = current_target; + target = Vector3MoveTowards( + target, target_target, + CAMERA_SMOOTH_SPEED * GetFrameTime() * + Vector3Length(Vector3Subtract(target, target_target))); } - if (mouse.x >= GetScreenWidth() / 2.0 && mouse.y >= MENU_HEIGHT) { - float wheel = GetMouseWheelMove(); - if (IsKeyDown(KEY_LEFT_SHIFT)) { - distance -= wheel * ZOOM_SPEED * ZOOM_MULTIPLIER; - } else { - distance -= wheel * ZOOM_SPEED; - } - } distance = Clamp(distance, MIN_CAMERA_DISTANCE, MAX_CAMERA_DISTANCE); // Spherical coordinates diff --git a/src/main.cpp b/src/main.cpp index 9b6cfbe..2a4794a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -23,7 +23,6 @@ // - Click states to display them in the board // - Find shortest path to any winning state and mark it in the graph // - Also mark the next move along the path on the board -// TODO: Smooth camera (on target change) // TODO: Mark the starting state // TODO: Mark the visited states