aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/manager
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/manager')
-rw-r--r--src/crepe/manager/CMakeLists.txt2
-rw-r--r--src/crepe/manager/EventManager.cpp6
-rw-r--r--src/crepe/manager/EventManager.h23
-rw-r--r--src/crepe/manager/LoopTimerManager.cpp77
-rw-r--r--src/crepe/manager/LoopTimerManager.h145
-rw-r--r--src/crepe/manager/Mediator.h11
6 files changed, 236 insertions, 28 deletions
diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt
index 517b8a2..29d6df0 100644
--- a/src/crepe/manager/CMakeLists.txt
+++ b/src/crepe/manager/CMakeLists.txt
@@ -4,6 +4,7 @@ target_sources(crepe PUBLIC
Manager.cpp
SaveManager.cpp
SceneManager.cpp
+ LoopTimerManager.cpp
)
target_sources(crepe PUBLIC FILE_SET HEADERS FILES
@@ -16,5 +17,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES
SaveManager.h
SceneManager.h
SceneManager.hpp
+ LoopTimerManager.h
)
diff --git a/src/crepe/manager/EventManager.cpp b/src/crepe/manager/EventManager.cpp
index 20f0dd3..9b0fa95 100644
--- a/src/crepe/manager/EventManager.cpp
+++ b/src/crepe/manager/EventManager.cpp
@@ -3,11 +3,9 @@
using namespace crepe;
using namespace std;
-EventManager & EventManager::get_instance() {
- static EventManager instance;
- return instance;
+EventManager::EventManager(Mediator & mediator) : Manager(mediator){
+ this->mediator.event_manager = *this;
}
-
void EventManager::dispatch_events() {
for (auto & event : this->events_queue) {
this->handle_event(event.type, event.channel, *event.event.get());
diff --git a/src/crepe/manager/EventManager.h b/src/crepe/manager/EventManager.h
index ba5e98b..30b929c 100644
--- a/src/crepe/manager/EventManager.h
+++ b/src/crepe/manager/EventManager.h
@@ -8,6 +8,8 @@
#include "../api/Event.h"
#include "../api/EventHandler.h"
+#include "Manager.h"
+
namespace crepe {
//! Event listener unique ID
@@ -22,27 +24,16 @@ typedef size_t subscription_t;
typedef size_t event_channel_t;
/**
- * \class EventManager
* \brief Manages event subscriptions, triggers, and queues, enabling decoupled event handling.
*
* The `EventManager` acts as a centralized event system. It allows for registering callbacks
* for specific event types, triggering events synchronously, queueing events for later
* processing, and managing subscriptions via unique identifiers.
*/
-class EventManager {
+class EventManager : public Manager {
public:
static constexpr const event_channel_t CHANNEL_ALL = -1;
-
- /**
- * \brief Get the singleton instance of the EventManager.
- *
- * This method returns the unique instance of the EventManager, creating it if it
- * doesn't already exist. Ensures only one instance is active in the program.
- *
- * \return Reference to the singleton instance of the EventManager.
- */
- static EventManager & get_instance();
-
+ EventManager(Mediator & mediator);
/**
* \brief Subscribe to a specific event type.
*
@@ -107,12 +98,6 @@ public:
void clear();
private:
- /**
- * \brief Default constructor for the EventManager.
- *
- * Constructor is private to enforce the singleton pattern.
- */
- EventManager() = default;
/**
* \struct QueueEntry
diff --git a/src/crepe/manager/LoopTimerManager.cpp b/src/crepe/manager/LoopTimerManager.cpp
new file mode 100644
index 0000000..2379fdd
--- /dev/null
+++ b/src/crepe/manager/LoopTimerManager.cpp
@@ -0,0 +1,77 @@
+#include <chrono>
+#include <thread>
+
+#include "../facade/SDLContext.h"
+#include "../util/Log.h"
+
+#include "LoopTimerManager.h"
+
+using namespace crepe;
+
+LoopTimerManager::LoopTimerManager(Mediator & mediator) : Manager(mediator) {
+ this->mediator.loop_timer = *this;
+ dbg_trace();
+ }
+
+void LoopTimerManager::start() {
+ this->last_frame_time = std::chrono::steady_clock::now();
+
+ this->elapsed_time = std::chrono::milliseconds(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<std::chrono::milliseconds>(fixed_delta_time);
+ this->delta_time = std::chrono::milliseconds(0);
+}
+
+void LoopTimerManager::update() {
+ auto current_frame_time = std::chrono::steady_clock::now();
+ // Convert to duration in seconds for delta time
+ this->delta_time = std::chrono::duration_cast<std::chrono::duration<double>>(
+ current_frame_time - last_frame_time);
+
+ if (this->delta_time > this->maximum_delta_time) {
+ this->delta_time = this->maximum_delta_time;
+ }
+ this->actual_fps = 1.0 / this->delta_time.count();
+
+ this->elapsed_time += this->delta_time;
+ this->last_frame_time = current_frame_time;
+}
+
+double LoopTimerManager::get_delta_time() const { return this->delta_time.count() * this->time_scale; }
+
+double LoopTimerManager::get_current_time() const { return this->elapsed_time.count(); }
+
+void LoopTimerManager::advance_fixed_update() { this->elapsed_fixed_time += this->fixed_delta_time; }
+
+double LoopTimerManager::get_fixed_delta_time() const { return this->fixed_delta_time.count(); }
+
+void LoopTimerManager::set_target_fps(int fps) {
+ this->target_fps = fps;
+ // target time per frame in seconds
+ this->frame_target_time = std::chrono::duration<double>(1.0) / this->target_fps;
+}
+
+int LoopTimerManager::get_fps() const { return this->actual_fps; }
+
+void LoopTimerManager::set_time_scale(double value) { this->time_scale = value; }
+
+double LoopTimerManager::get_time_scale() const { return this->time_scale; }
+void LoopTimerManager::enforce_frame_rate() {
+ auto current_frame_time = std::chrono::steady_clock::now();
+ auto 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) {
+ auto delay_time = std::chrono::duration_cast<std::chrono::microseconds>(
+ this->frame_target_time - frame_duration);
+
+ if (delay_time.count() > 0) {
+ std::this_thread::sleep_for(delay_time);
+ }
+ }
+}
+
+double LoopTimerManager::get_lag() const {
+ return (this->elapsed_time - this->elapsed_fixed_time).count();
+}
diff --git a/src/crepe/manager/LoopTimerManager.h b/src/crepe/manager/LoopTimerManager.h
new file mode 100644
index 0000000..cd05bf2
--- /dev/null
+++ b/src/crepe/manager/LoopTimerManager.h
@@ -0,0 +1,145 @@
+#pragma once
+
+#include <chrono>
+
+#include "Manager.h"
+
+namespace crepe {
+
+/**
+ * \brief Manages timing and frame rate for the game loop.
+ *
+ * The LoopTimerManager class is responsible for calculating and managing timing functions
+ * such as delta time, frames per second (FPS), fixed time steps, and time scaling. It ensures
+ * consistent frame updates and supports game loop operations, such as handling fixed updates
+ * for physics and other time-sensitive operations.
+ */
+class LoopTimerManager : public Manager {
+public:
+ LoopTimerManager(Mediator & mediator);
+ /**
+ * \brief Get the current delta time for the current frame.
+ *
+ * \return Delta time in seconds since the last frame.
+ */
+ double get_delta_time() const;
+
+ /**
+ * \brief Get the current game time.
+ *
+ * \note The current game time may vary from real-world elapsed time. It is the cumulative
+ * sum of each frame's delta time.
+ *
+ * \return Elapsed game time in seconds.
+ */
+ double get_current_time() const;
+
+ /**
+ * \brief Set the target frames per second (FPS).
+ *
+ * \param fps The desired frames rendered per second.
+ */
+ void set_target_fps(int fps);
+
+ /**
+ * \brief Get the current frames per second (FPS).
+ *
+ * \return Current FPS.
+ */
+ int get_fps() const;
+
+ /**
+ * \brief Get the current time scale.
+ *
+ * \return The current time scale, where (0 = pause, < 1 = slow down, 1 = normal speed, > 1 = speed up).
+ * up the game.
+ */
+ double get_time_scale() const;
+
+ /**
+ * \brief Set the time scale.
+ *
+ * time_scale is a value that changes the delta time that can be retrieved using get_delta_time function.
+ *
+ * \param time_scale The desired time scale (0 = pause, < 1 = slow down, 1 = normal speed, > 1 = speed up).
+ */
+ void set_time_scale(double time_scale);
+
+private:
+ friend class LoopManager;
+
+ /**
+ * \brief Start the loop timer.
+ *
+ * Initializes the timer to begin tracking frame times.
+ */
+ void start();
+ /**
+ * \brief Enforce the frame rate limit.
+ *
+ * Ensures that the game loop does not exceed the target FPS by delaying frame updates as
+ * necessary.
+ */
+ void enforce_frame_rate();
+
+ /**
+ * \brief Get the fixed delta time for consistent updates.
+ *
+ * Fixed delta time is used for operations that require uniform time steps, such as physics
+ * calculations.
+ *
+ * \return Fixed delta time in seconds.
+ */
+ double get_fixed_delta_time() const;
+
+ /**
+ * \brief Get the accumulated lag in the game loop.
+ *
+ * Lag represents the difference between the target frame time and the actual frame time,
+ * useful for managing fixed update intervals.
+ *
+ * \return Accumulated lag in seconds.
+ */
+ double get_lag() const;
+
+ /**
+ * \brief Update the timer to the current frame.
+ *
+ * Calculates and updates the delta time for the current frame and adds it to the cumulative
+ * game time.
+ */
+ void update();
+
+ /**
+ * \brief Advance the game loop by a fixed update interval.
+ *
+ * This method progresses the game state by a consistent, fixed time step, allowing for
+ * stable updates independent of frame rate fluctuations.
+ */
+ void advance_fixed_update();
+
+private:
+ //! Target frames per second
+ int target_fps = 50;
+ //! Actual frames per second
+ int actual_fps = 0;
+ //! time scale for speeding up or slowing down the game (0 = pause, < 1 = slow down, 1 = normal speed, > 1 = speed up)
+ double time_scale = 1;
+ //! Maximum delta time in seconds to avoid large jumps
+ std::chrono::duration<double> maximum_delta_time{0.25};
+ //! Delta time for the current frame in seconds
+ std::chrono::duration<double> delta_time{0.0};
+ //! Target time per frame in seconds
+ std::chrono::duration<double> frame_target_time
+ = std::chrono::duration<double>(1.0) / target_fps;
+ //! Fixed delta time for fixed updates in seconds
+ std::chrono::duration<double> fixed_delta_time = std::chrono::duration<double>(1.0) / 50.0;
+ //! Total elapsed game time in seconds
+ std::chrono::duration<double> elapsed_time{0.0};
+ //! Total elapsed time for fixed updates in seconds
+ std::chrono::duration<double> elapsed_fixed_time{0.0};
+ //! Time of the last frame
+ std::chrono::steady_clock::time_point last_frame_time;
+};
+
+} // namespace crepe
diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h
index 8094d80..987f4d4 100644
--- a/src/crepe/manager/Mediator.h
+++ b/src/crepe/manager/Mediator.h
@@ -4,15 +4,16 @@
// TODO: remove these singletons:
#include "../facade/SDLContext.h"
-#include "EventManager.h"
+//#include "EventManager.h"
#include "SaveManager.h"
-#include "api/LoopTimer.h"
+//#include "LoopTimerManager.h"
namespace crepe {
class ComponentManager;
class SceneManager;
-
+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
@@ -28,10 +29,10 @@ class SceneManager;
struct Mediator {
OptionalRef<ComponentManager> component_manager;
OptionalRef<SceneManager> scene_manager;
+ OptionalRef<EventManager> event_manager;
+ OptionalRef<LoopTimerManager> loop_timer;
OptionalRef<SaveManager> save_manager = SaveManager::get_instance();
- OptionalRef<EventManager> event_manager = EventManager::get_instance();
OptionalRef<SDLContext> sdl_context = SDLContext::get_instance();
- OptionalRef<LoopTimer> timer = LoopTimer::get_instance();
};
} // namespace crepe