diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-12-11 15:01:46 +0100 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-12-11 15:01:46 +0100 |
commit | e49893e8de74534494792955c50ea0eabaf3ba38 (patch) | |
tree | c85a80001d4c17e467d69698defb628109559ecf | |
parent | 68bf20b491b4b7673c2ece7a6497b9faffd44eb1 (diff) |
WIP fix LoopTimerManager
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 19 | ||||
-rw-r--r-- | src/crepe/manager/LoopTimerManager.cpp | 47 | ||||
-rw-r--r-- | src/crepe/manager/LoopTimerManager.h | 34 | ||||
-rw-r--r-- | src/crepe/manager/Mediator.h | 6 | ||||
-rw-r--r-- | src/crepe/system/AISystem.cpp | 8 | ||||
-rw-r--r-- | src/test/LoopTimerTest.cpp | 10 |
6 files changed, 64 insertions, 60 deletions
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 4ca9928..aa4a21a 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -43,20 +43,19 @@ void LoopManager::setup() { void LoopManager::loop() { try { + while (game_running) { + this->loop_timer.update(); - while (game_running) { - this->loop_timer.update(); + while (this->loop_timer.get_lag() >= this->loop_timer.get_fixed_delta_time()) { + this->fixed_update(); + this->loop_timer.advance_fixed_elapsed_time(); + } - while (this->loop_timer.get_lag() >= this->loop_timer.get_fixed_delta_time()) { - this->fixed_update(); - this->loop_timer.advance_fixed_elapsed_time(); + this->frame_update(); + this->loop_timer.enforce_frame_rate(); } - - this->frame_update(); - this->loop_timer.enforce_frame_rate(); - } }catch(const exception & e){ - Log::logf(Log::Level::ERROR, "Exception caught in main loop: %s", e.what()); + Log::logf(Log::Level::ERROR, "Exception caught in main loop: {}", e.what()); this->event_manager.trigger_event<ShutDownEvent>(ShutDownEvent{}); } } diff --git a/src/crepe/manager/LoopTimerManager.cpp b/src/crepe/manager/LoopTimerManager.cpp index a306eb7..92a2150 100644 --- a/src/crepe/manager/LoopTimerManager.cpp +++ b/src/crepe/manager/LoopTimerManager.cpp @@ -6,7 +6,9 @@ #include "LoopTimerManager.h" using namespace crepe; +using namespace std::chrono; using namespace std::chrono_literals; + LoopTimerManager::LoopTimerManager(Mediator & mediator) : Manager(mediator) { this->mediator.loop_timer = *this; dbg_trace(); @@ -15,15 +17,14 @@ LoopTimerManager::LoopTimerManager(Mediator & mediator) : Manager(mediator) { void LoopTimerManager::start() { this->last_frame_time = std::chrono::steady_clock::now(); - this->elapsed_time = 0s; + this->elapsed_time = elapsed_time_t{0}; // by starting the elapsed_fixed_time at (0 - fixed_delta_time) in milliseconds it calls a fixed update at the start of the loop. - this->elapsed_fixed_time - = -std::chrono::duration_cast<ElapsedTime_t>(this->fixed_delta_time); - this->delta_time = 0s; + // this->elapsed_fixed_time = -this->fixed_delta_time; + this->delta_time = duration_t{0}; } void LoopTimerManager::update() { - TimePoint_t current_frame_time + time_point_t current_frame_time = std::chrono::steady_clock::now(); // Convert to duration in seconds for delta time this->delta_time = current_frame_time - last_frame_time; @@ -32,20 +33,20 @@ void LoopTimerManager::update() { this->delta_time = this->maximum_delta_time; } if (this->delta_time > 0s) { - this->actual_fps = 1.0 / this->delta_time.count(); + this->actual_fps = 1.0 / duration_cast<seconds>(this->delta_time).count(); } else { this->actual_fps = 0; } - this->elapsed_time += std::chrono::duration_cast<ElapsedTime_t>(this->delta_time); + this->elapsed_time += duration_cast<elapsed_time_t>(this->delta_time); this->last_frame_time = current_frame_time; } -Duration_t LoopTimerManager::get_delta_time() const {return this->delta_time * this->time_scale;} +duration_t LoopTimerManager::get_delta_time() const {return this->delta_time * this->time_scale;} -ElapsedTime_t LoopTimerManager::get_elapsed_time() const { return this->elapsed_time; } +elapsed_time_t LoopTimerManager::get_elapsed_time() const { return this->elapsed_time; } void LoopTimerManager::advance_fixed_elapsed_time() { - this->elapsed_fixed_time += std::chrono::duration_cast<ElapsedTime_t>(this->fixed_delta_time); + this->elapsed_fixed_time += std::chrono::duration_cast<elapsed_time_t>(this->fixed_delta_time); } void LoopTimerManager::set_target_framerate(unsigned fps) { @@ -53,7 +54,7 @@ void LoopTimerManager::set_target_framerate(unsigned fps) { //check if fps is lower or equals 0 if (fps <= 0) return; // target time per frame in seconds - this->frame_target_time = Duration_t(1s) / this->target_fps; + this->frame_target_time = duration_t(1s) / this->target_fps; } unsigned LoopTimerManager::get_fps() const { return this->actual_fps; } @@ -63,32 +64,30 @@ void LoopTimerManager::set_time_scale(double value) { this->time_scale = value; float LoopTimerManager::get_time_scale() const { return this->time_scale; } void LoopTimerManager::enforce_frame_rate() { - TimePoint_t current_frame_time - = std::chrono::steady_clock::now(); - Duration_t frame_duration = current_frame_time - this->last_frame_time; + time_point_t current_frame_time = std::chrono::steady_clock::now(); + duration_t frame_duration = current_frame_time - this->last_frame_time; + // Check if frame duration is less than the target frame time if (frame_duration < this->frame_target_time) { - std::chrono::microseconds delay_time - = std::chrono::duration_cast<std::chrono::microseconds>(this->frame_target_time - - frame_duration); - - if (delay_time.count() > 0) { + duration_t delay_time = this->frame_target_time - frame_duration; + if (delay_time > 0s) { std::this_thread::sleep_for(delay_time); } } } -Duration_t LoopTimerManager::get_lag() const { - return (this->elapsed_time - this->elapsed_fixed_time); +duration_t LoopTimerManager::get_lag() const { + return this->elapsed_time - this->elapsed_fixed_time; } -Duration_t LoopTimerManager::get_scaled_fixed_delta_time() const { +duration_t LoopTimerManager::get_scaled_fixed_delta_time() const { return this->fixed_delta_time * this->time_scale; } + void LoopTimerManager::set_fixed_delta_time(float seconds) { - this->fixed_delta_time = Duration_t(seconds); + this->fixed_delta_time = duration_t(seconds); } -Duration_t LoopTimerManager::get_fixed_delta_time() const { +duration_t LoopTimerManager::get_fixed_delta_time() const { return this->fixed_delta_time; } diff --git a/src/crepe/manager/LoopTimerManager.h b/src/crepe/manager/LoopTimerManager.h index c5f3cb0..ad522f7 100644 --- a/src/crepe/manager/LoopTimerManager.h +++ b/src/crepe/manager/LoopTimerManager.h @@ -5,9 +5,10 @@ #include "Manager.h" namespace crepe { -typedef std::chrono::duration<float> Duration_t; -typedef std::chrono::duration<unsigned long long, std::micro> ElapsedTime_t; -typedef std::chrono::steady_clock::time_point TimePoint_t; + +typedef std::chrono::duration<float> duration_t; +typedef std::chrono::duration<unsigned long long, std::micro> elapsed_time_t; + /** * \brief Manages timing and frame rate for the game loop. * @@ -30,7 +31,7 @@ public: * * \return Delta time in seconds since the last frame. */ - Duration_t get_delta_time() const; + duration_t get_delta_time() const; /** * \brief Get the current elapsed time (total time passed ) @@ -40,7 +41,7 @@ public: * * \return Elapsed game time in seconds. */ - ElapsedTime_t get_elapsed_time() const; + elapsed_time_t get_elapsed_time() const; /** * \brief Set the target frames per second (FPS). @@ -81,7 +82,7 @@ public: * * \return The unscaled fixed delta time in seconds. */ - Duration_t get_fixed_delta_time() const; + duration_t get_fixed_delta_time() const; /** * \brief Set the fixed_delta_time in seconds. @@ -102,7 +103,7 @@ public: * * \return The fixed delta time, scaled by the current time scale, in seconds. */ - Duration_t get_scaled_fixed_delta_time() const; + duration_t get_scaled_fixed_delta_time() const; private: //! Friend relation to use start,enforce_frame_rate,get_lag,update,advance_fixed_update. @@ -128,7 +129,7 @@ private: * * \return Accumulated lag in seconds. */ - Duration_t get_lag() const; + duration_t get_lag() const; /** * \brief Update the timer to the current frame. @@ -154,20 +155,21 @@ private: //! Time scale for speeding up or slowing down the game (0 = pause, < 1 = slow down, 1 = normal speed, > 1 = speed up). float time_scale = 1; //! Maximum delta time in seconds to avoid large jumps. - Duration_t maximum_delta_time{0.25}; + duration_t maximum_delta_time{0.25}; //! Delta time for the current frame in seconds. - Duration_t delta_time{0.0}; + duration_t delta_time{0.0}; //! Target time per frame in seconds - Duration_t frame_target_time - = Duration_t(1.0) / target_fps; + duration_t frame_target_time{1.0 / target_fps}; //! Fixed delta time for fixed updates in seconds. - Duration_t fixed_delta_time = Duration_t(1.0) / 50.0; + duration_t fixed_delta_time{1.0 / 50.0}; //! Total elapsed game time in microseconds. - ElapsedTime_t elapsed_time{0}; + elapsed_time_t elapsed_time{0}; //! Total elapsed time for fixed updates in microseconds. - ElapsedTime_t elapsed_fixed_time{0}; + elapsed_time_t elapsed_fixed_time{0}; + + typedef std::chrono::steady_clock::time_point time_point_t; //! Time of the last frame. - TimePoint_t last_frame_time; + time_point_t last_frame_time; }; } // namespace crepe diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index dfb37dc..b529f2c 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -5,17 +5,15 @@ // TODO: remove these singletons: #include "../facade/SDLContext.h" -#include "SaveManager.h" - namespace crepe { class ComponentManager; class SceneManager; +class EventManager; +class LoopTimerManager; class SaveManager; class ResourceManager; -class LoopTimerManager; -class EventManager; /** * Struct to pass references to classes that would otherwise need to be singletons down to * other classes within the engine hierarchy. Made to prevent constant changes to subclasses to diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index e2e36a5..ffb1bcd 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,21 +1,23 @@ #include <algorithm> #include <cmath> -#include "api/LoopTimer.h" +#include "manager/LoopTimerManager.h" #include "manager/ComponentManager.h" #include "manager/Mediator.h" #include "AISystem.h" using namespace crepe; +using namespace std::chrono; void AISystem::update() { const Mediator & mediator = this->mediator; ComponentManager & mgr = mediator.component_manager; RefVector<AI> ai_components = mgr.get_components_by_type<AI>(); + LoopTimerManager & loop_timer = mediator.loop_timer; //TODO: Use fixed loop dt (this is not available at master at the moment) - double dt = LoopTimer::get_instance().get_delta_time(); + duration_t dt = loop_timer.get_delta_time(); // Loop through all AI components for (AI & ai : ai_components) { @@ -42,7 +44,7 @@ void AISystem::update() { // Calculate the acceleration (using the above calculated force) vec2 acceleration = force / rigidbody.data.mass; // Finally, update Rigidbody's velocity - rigidbody.data.linear_velocity += acceleration * dt; + rigidbody.data.linear_velocity += acceleration * duration_cast<seconds>(dt).count(); } } diff --git a/src/test/LoopTimerTest.cpp b/src/test/LoopTimerTest.cpp index 1216e5e..f99f109 100644 --- a/src/test/LoopTimerTest.cpp +++ b/src/test/LoopTimerTest.cpp @@ -15,6 +15,7 @@ protected: void SetUp() override { loop_timer.start(); } }; + TEST_F(LoopTimerTest, EnforcesTargetFrameRate) { // Set the target FPS to 60 (which gives a target time per frame of ~16.67 ms) loop_timer.set_target_framerate(60); @@ -28,15 +29,17 @@ TEST_F(LoopTimerTest, EnforcesTargetFrameRate) { // For 60 FPS, the target frame time is around 16.67ms ASSERT_NEAR(elapsed_ms, 16.7, 1); } + TEST_F(LoopTimerTest, SetTargetFps) { // Set the target FPS to 120 loop_timer.set_target_framerate(120); // Calculate the expected frame time (~8.33ms per frame) - Duration_t expected_frame_time = std::chrono::duration<float>(1.0 / 120.0); + duration_t expected_frame_time = std::chrono::duration<float>(1.0 / 120.0); ASSERT_NEAR(loop_timer.frame_target_time.count(), expected_frame_time.count(), 0.001); } + TEST_F(LoopTimerTest, DeltaTimeCalculation) { // Set the target FPS to 60 (16.67 ms per frame) loop_timer.set_target_framerate(60); @@ -46,7 +49,7 @@ TEST_F(LoopTimerTest, DeltaTimeCalculation) { auto end_time = steady_clock::now(); // Check the delta time - Duration_t delta_time = loop_timer.get_delta_time(); + duration_t delta_time = loop_timer.get_delta_time(); auto elapsed_time = duration_cast<seconds>(end_time - start_time).count(); @@ -68,8 +71,9 @@ TEST_F(LoopTimerTest, getCurrentTime) { auto end_time = steady_clock::now(); // Get the elapsed time in seconds as a double - auto elapsed_time = std::chrono::duration_cast<ElapsedTime_t>(end_time - start_time).count(); + auto elapsed_time = std::chrono::duration_cast<elapsed_time_t>(end_time - start_time).count(); ASSERT_NEAR(loop_timer.get_elapsed_time().count(), elapsed_time, 5); } + |