diff options
Diffstat (limited to 'src/crepe')
| -rw-r--r-- | src/crepe/api/CMakeLists.txt | 6 | ||||
| -rw-r--r-- | src/crepe/api/IKeyListener.cpp | 19 | ||||
| -rw-r--r-- | src/crepe/api/IKeyListener.h | 50 | ||||
| -rw-r--r-- | src/crepe/api/IMouseListener.cpp | 29 | ||||
| -rw-r--r-- | src/crepe/api/IMouseListener.h | 73 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 77 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.h | 60 | ||||
| -rw-r--r-- | src/crepe/api/LoopTimer.h | 138 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.cpp | 4 | ||||
| -rw-r--r-- | src/crepe/manager/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/crepe/manager/EventManager.cpp | 6 | ||||
| -rw-r--r-- | src/crepe/manager/EventManager.h | 23 | ||||
| -rw-r--r-- | src/crepe/manager/LoopTimerManager.cpp | 91 | ||||
| -rw-r--r-- | src/crepe/manager/LoopTimerManager.h | 175 | ||||
| -rw-r--r-- | src/crepe/manager/Mediator.h | 9 | ||||
| -rw-r--r-- | src/crepe/manager/SceneManager.cpp | 3 | ||||
| -rw-r--r-- | src/crepe/system/AISystem.cpp | 10 | ||||
| -rw-r--r-- | src/crepe/system/AnimatorSystem.cpp | 6 | 
18 files changed, 355 insertions, 426 deletions
| diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 46deb67..fb11c8d 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -13,10 +13,7 @@ target_sources(crepe PUBLIC  	Animator.cpp  	BoxCollider.cpp  	CircleCollider.cpp -	IKeyListener.cpp -	IMouseListener.cpp  	LoopManager.cpp -	LoopTimer.cpp  	Asset.cpp  	EventHandler.cpp  	Script.cpp @@ -47,10 +44,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	EventHandler.h  	EventHandler.hpp  	Event.h -	IKeyListener.h -	IMouseListener.h  	LoopManager.h -	LoopTimer.h  	Asset.h  	Button.h  	UIObject.h diff --git a/src/crepe/api/IKeyListener.cpp b/src/crepe/api/IKeyListener.cpp deleted file mode 100644 index 8642655..0000000 --- a/src/crepe/api/IKeyListener.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "IKeyListener.h" - -using namespace crepe; - -// Constructor with specified channel -IKeyListener::IKeyListener(event_channel_t channel) -	: event_manager(EventManager::get_instance()) { -	this->press_id = event_manager.subscribe<KeyPressEvent>( -		[this](const KeyPressEvent & event) { return this->on_key_pressed(event); }, channel); -	this->release_id = event_manager.subscribe<KeyReleaseEvent>( -		[this](const KeyReleaseEvent & event) { return this->on_key_released(event); }, -		channel); -} - -// Destructor, unsubscribe events -IKeyListener::~IKeyListener() { -	event_manager.unsubscribe(this->press_id); -	event_manager.unsubscribe(this->release_id); -} diff --git a/src/crepe/api/IKeyListener.h b/src/crepe/api/IKeyListener.h deleted file mode 100644 index 180a0a6..0000000 --- a/src/crepe/api/IKeyListener.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once - -#include "../manager/EventManager.h" - -#include "Event.h" -#include "EventHandler.h" - -namespace crepe { - -/** - * \class IKeyListener - * \brief Interface for keyboard event handling in the application. - */ -class IKeyListener { -public: -	/** -	 * \brief Constructs an IKeyListener with a specified channel. -	 * \param channel The channel ID for event handling. -	 */ -	IKeyListener(event_channel_t channel = EventManager::CHANNEL_ALL); -	virtual ~IKeyListener(); -	IKeyListener(const IKeyListener &) = delete; -	IKeyListener & operator=(const IKeyListener &) = delete; -	IKeyListener & operator=(IKeyListener &&) = delete; -	IKeyListener(IKeyListener &&) = delete; - -	/** -	 * \brief Pure virtual function to handle key press events. -	 * \param event The key press event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_key_pressed(const KeyPressEvent & event) = 0; - -	/** -	 * \brief Pure virtual function to handle key release events. -	 * \param event The key release event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_key_released(const KeyReleaseEvent & event) = 0; - -private: -	//! Key press event id -	subscription_t press_id = -1; -	//! Key release event id -	subscription_t release_id = -1; -	//! EventManager reference -	EventManager & event_manager; -}; - -} // namespace crepe diff --git a/src/crepe/api/IMouseListener.cpp b/src/crepe/api/IMouseListener.cpp deleted file mode 100644 index 989aeb3..0000000 --- a/src/crepe/api/IMouseListener.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "IMouseListener.h" - -using namespace crepe; - -IMouseListener::IMouseListener(event_channel_t channel) -	: event_manager(EventManager::get_instance()) { -	this->click_id = event_manager.subscribe<MouseClickEvent>( -		[this](const MouseClickEvent & event) { return this->on_mouse_clicked(event); }, -		channel); - -	this->press_id = event_manager.subscribe<MousePressEvent>( -		[this](const MousePressEvent & event) { return this->on_mouse_pressed(event); }, -		channel); - -	this->release_id = event_manager.subscribe<MouseReleaseEvent>( -		[this](const MouseReleaseEvent & event) { return this->on_mouse_released(event); }, -		channel); - -	this->move_id = event_manager.subscribe<MouseMoveEvent>( -		[this](const MouseMoveEvent & event) { return this->on_mouse_moved(event); }, channel); -} - -IMouseListener::~IMouseListener() { -	// Unsubscribe event handlers -	event_manager.unsubscribe(this->click_id); -	event_manager.unsubscribe(this->press_id); -	event_manager.unsubscribe(this->release_id); -	event_manager.unsubscribe(this->move_id); -} diff --git a/src/crepe/api/IMouseListener.h b/src/crepe/api/IMouseListener.h deleted file mode 100644 index e19897d..0000000 --- a/src/crepe/api/IMouseListener.h +++ /dev/null @@ -1,73 +0,0 @@ -#pragma once - -#include "../manager/EventManager.h" - -#include "Event.h" -#include "EventHandler.h" - -namespace crepe { - -/** - * \class IMouseListener - * \brief Interface for mouse event handling in the application. - */ -class IMouseListener { -public: -	/** -	 * \brief Constructs an IMouseListener with a specified channel. -	 * \param channel The channel ID for event handling. -	 */ -	IMouseListener(event_channel_t channel = EventManager::CHANNEL_ALL); -	virtual ~IMouseListener(); -	IMouseListener & operator=(const IMouseListener &) = delete; -	IMouseListener(const IMouseListener &) = delete; -	IMouseListener & operator=(const IMouseListener &&) = delete; -	IMouseListener(IMouseListener &&) = delete; - -	/** -	 * \brief Move assignment operator (deleted). -	 */ -	IMouseListener & operator=(IMouseListener &&) = delete; - -	/** -	 * \brief Handles a mouse click event. -	 * \param event The mouse click event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_mouse_clicked(const MouseClickEvent & event) = 0; - -	/** -	 * \brief Handles a mouse press event. -	 * \param event The mouse press event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_mouse_pressed(const MousePressEvent & event) = 0; - -	/** -	 * \brief Handles a mouse release event. -	 * \param event The mouse release event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_mouse_released(const MouseReleaseEvent & event) = 0; - -	/** -	 * \brief Handles a mouse move event. -	 * \param event The mouse move event to handle. -	 * \return True if the event was handled, false otherwise. -	 */ -	virtual bool on_mouse_moved(const MouseMoveEvent & event) = 0; - -private: -	//! Mouse click event id -	subscription_t click_id = -1; -	//! Mouse press event id -	subscription_t press_id = -1; -	//! Mouse release event id -	subscription_t release_id = -1; -	//! Mouse move event id -	subscription_t move_id = -1; -	//! EventManager reference -	EventManager & event_manager; -}; - -} //namespace crepe diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 1f0ba72..b5e5ff7 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,3 +1,6 @@ +#include "../facade/SDLContext.h" +#include "../manager/EventManager.h" +#include "../manager/LoopTimerManager.h"  #include "../system/AISystem.h"  #include "../system/AnimatorSystem.h"  #include "../system/AudioSystem.h" @@ -7,7 +10,7 @@  #include "../system/PhysicsSystem.h"  #include "../system/RenderSystem.h"  #include "../system/ScriptSystem.h" -#include "manager/EventManager.h" +#include "../util/Log.h"  #include "LoopManager.h" @@ -22,62 +25,62 @@ LoopManager::LoopManager() {  	this->load_system<RenderSystem>();  	this->load_system<ScriptSystem>();  	this->load_system<InputSystem>(); +	this->event_manager.subscribe<ShutDownEvent>( +		[this](const ShutDownEvent & event) { return this->on_shutdown(event); });  	this->load_system<AudioSystem>();  	this->load_system<AISystem>();  } - -void LoopManager::process_input() { this->get_system<InputSystem>().update(); } -  void LoopManager::start() {  	this->setup();  	this->loop();  } -void LoopManager::set_running(bool running) { this->game_running = running; } -void LoopManager::fixed_update() { -	// TODO: retrieve EventManager from direct member after singleton refactor -	EventManager & ev = this->mediator.event_manager; -	ev.dispatch_events(); -	this->get_system<ScriptSystem>().update(); -	this->get_system<AISystem>().update(); -	this->get_system<PhysicsSystem>().update(); -	this->get_system<CollisionSystem>().update(); -	this->get_system<AudioSystem>().update(); +void LoopManager::setup() { +	this->game_running = true; +	this->loop_timer.start(); +	this->scene_manager.load_next_scene();  }  void LoopManager::loop() { -	LoopTimer & timer = this->loop_timer; -	timer.start(); +	try { +		while (game_running) { +			this->loop_timer.update(); -	while (game_running) { -		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 (timer.get_lag() >= timer.get_fixed_delta_time()) { -			this->process_input(); -			this->fixed_update(); -			timer.advance_fixed_update(); +			this->frame_update(); +			this->loop_timer.enforce_frame_rate();  		} - -		this->update(); -		this->render(); - -		timer.enforce_frame_rate(); +	} catch (const exception & e) { +		Log::logf(Log::Level::ERROR, "Exception caught in main loop: {}", e.what()); +		this->event_manager.trigger_event<ShutDownEvent>(ShutDownEvent{});  	}  } -void LoopManager::setup() { -	LoopTimer & timer = this->loop_timer; -	this->game_running = true; -	this->scene_manager.load_next_scene(); -	timer.start(); -	timer.set_fps(200); +// will be called at a fixed interval +void LoopManager::fixed_update() { +	this->get_system<InputSystem>().update(); +	this->event_manager.dispatch_events(); +	this->get_system<ScriptSystem>().update(); +	this->get_system<AISystem>().update(); +	this->get_system<PhysicsSystem>().update(); +	this->get_system<CollisionSystem>().update(); +	this->get_system<AudioSystem>().update();  } -void LoopManager::render() { -	if (!this->game_running) return; - +// will be called every frame +void LoopManager::frame_update() { +	this->scene_manager.load_next_scene();  	this->get_system<AnimatorSystem>().update(); +	//render  	this->get_system<RenderSystem>().update();  } -void LoopManager::update() {} +bool LoopManager::on_shutdown(const ShutDownEvent & e) { +	this->game_running = false; +	// propagate to possible user ShutDownEvent listeners +	return false; +} diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index 1bafa56..50d91d2 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -4,16 +4,17 @@  #include "../facade/SDLContext.h"  #include "../manager/ComponentManager.h" +#include "../manager/EventManager.h" +#include "../manager/LoopTimerManager.h" +#include "../manager/Mediator.h"  #include "../manager/ResourceManager.h"  #include "../manager/SaveManager.h"  #include "../manager/SceneManager.h"  #include "../system/System.h"  #include "LoopTimer.h" -#include "manager/ResourceManager.h"  namespace crepe { -  /**   * \brief Main game loop manager   * @@ -21,8 +22,14 @@ namespace crepe {   */  class LoopManager {  public: -	void start();  	LoopManager(); +	/** +	 * \brief Start the gameloop +	 * +	 * This is the start of the engine where the setup is called and then the loop keeps running until the game stops running. +	 * The Game programmer needs to call this function to run the game. This should be done after creating and adding all scenes. +	 */ +	void start();  	/**  	 * \brief Add a new concrete scene to the scene manager @@ -47,47 +54,20 @@ private:  	void loop();  	/** -	 * \brief Function for handling input-related system calls. -	 * -	 * Processes user inputs from keyboard and mouse. -	 */ -	void process_input(); - -	/**  	 * \brief Per-frame update.  	 *  	 * Updates the game state based on the elapsed time since the last frame.  	 */ -	void update(); - -	/** -	 * \brief Late update which is called after update(). -	 * -	 * This function can be used for final adjustments before rendering. -	 */ -	void late_update(); +	virtual void frame_update();  	/**  	 * \brief Fixed update executed at a fixed rate.  	 *  	 * This function updates physics and game logic based on LoopTimer's fixed_delta_time.  	 */ -	void fixed_update(); - -	/** -	 * \brief Set game running variable -	 * -	 * \param running running (false = game shutdown, true = game running) -	 */ -	void set_running(bool running); - -	/** -	 * \brief Function for executing render-related systems. -	 * -	 * Renders the current state of the game to the screen. -	 */ -	void render(); +	virtual void fixed_update(); +	//! Indicates whether the game is running.  	bool game_running = false;  private: @@ -98,21 +78,29 @@ private:  	ComponentManager component_manager{mediator};  	//! Scene manager instance  	SceneManager scene_manager{mediator}; +	//! LoopTimerManager instance +	LoopTimerManager loop_timer{mediator}; +	//! EventManager instance +	EventManager event_manager{mediator};  	//! Resource manager instance  	ResourceManager resource_manager{mediator};  	//! Save manager instance  	SaveManager save_manager{mediator};  	//! SDLContext instance  	SDLContext sdl_context{mediator}; -	//! LoopTimer instance -	LoopTimer loop_timer{mediator};  private:  	/** +	 * \brief Callback function for ShutDownEvent +	 * +	 * This function sets the game_running variable to false, stopping the gameloop and therefor quitting the game. +	 */ +	bool on_shutdown(const ShutDownEvent & e); +	/**  	 * \brief Collection of System instances  	 *  	 * This map holds System instances indexed by the system's class typeid. It is filled in the -	 * constructor of \c LoopManager using LoopManager::load_system. +	 * constructor of LoopManager using LoopManager::load_system.  	 */  	std::unordered_map<std::type_index, std::unique_ptr<System>> systems;  	/** diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h deleted file mode 100644 index 0a73a4c..0000000 --- a/src/crepe/api/LoopTimer.h +++ /dev/null @@ -1,138 +0,0 @@ -#pragma once - -#include "manager/Manager.h" -#include <chrono> - -namespace crepe { - -class LoopTimer : public Manager { -public: -	/** -	 * \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_fps(int fps); - -	/** -	 * \brief Get the current frames per second (FPS). -	 * -	 * \return Current FPS. -	 */ -	int get_fps() const; - -	/** -	 * \brief Get the current game scale. -	 * -	 * \return The current game scale, where 0 = paused, 1 = normal speed, and values > 1 speed -	 * up the game. -	 */ -	double get_game_scale() const; - -	/** -	 * \brief Set the game scale. -	 * -	 * \param game_scale The desired game scale (0 = pause, 1 = normal speed, > 1 = speed up). -	 */ -	void set_game_scale(double game_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 Construct a new LoopTimer object. -	 * -	 * Private constructor for singleton pattern to restrict instantiation outside the class. -	 */ -	LoopTimer(Mediator & mediator); - -	/** -	 * \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: -	//! Current frames per second -	int fps = 50; -	//! Current game scale -	double game_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) / 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/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 1dbd6a5..d71a9c8 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -340,8 +340,6 @@ SDLContext::CameraValues SDLContext::set_camera(const Camera & cam) {  	return ret_cam;  } -uint64_t SDLContext::get_ticks() const { return SDL_GetTicks64(); } -  std::unique_ptr<SDL_Texture, std::function<void(SDL_Texture *)>>  SDLContext::texture_from_path(const std::string & path) { @@ -372,8 +370,6 @@ ivec2 SDLContext::get_size(const Texture & ctx) {  	return size;  } -void SDLContext::delay(int ms) const { SDL_Delay(ms); } -  std::vector<SDLContext::EventData> SDLContext::get_events() {  	std::vector<SDLContext::EventData> event_list;  	SDL_Event event; diff --git a/src/crepe/manager/CMakeLists.txt b/src/crepe/manager/CMakeLists.txt index 480c8ee..f73e165 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  	ResourceManager.cpp  ) @@ -17,6 +18,7 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	SaveManager.h  	SceneManager.h  	SceneManager.hpp +	LoopTimerManager.h  	ResourceManager.h  	ResourceManager.hpp  ) diff --git a/src/crepe/manager/EventManager.cpp b/src/crepe/manager/EventManager.cpp index 20f0dd3..6aa49ee 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..639e37f 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,19 @@ 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. +	 * \param mediator A reference to a Mediator object used for transfering managers.  	 */ -	static EventManager & get_instance(); - +	EventManager(Mediator & mediator);  	/**  	 * \brief Subscribe to a specific event type.  	 * @@ -108,13 +102,6 @@ public:  private:  	/** -	 * \brief Default constructor for the EventManager. -	 * -	 * Constructor is private to enforce the singleton pattern. -	 */ -	EventManager() = default; - -	/**  	 * \struct QueueEntry  	 * \brief Represents an entry in the event queue.  	 */ diff --git a/src/crepe/manager/LoopTimerManager.cpp b/src/crepe/manager/LoopTimerManager.cpp new file mode 100644 index 0000000..9819632 --- /dev/null +++ b/src/crepe/manager/LoopTimerManager.cpp @@ -0,0 +1,91 @@ +#include <chrono> +#include <thread> + +#include "../util/Log.h" + +#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(); +} + +void LoopTimerManager::start() { +	this->last_frame_time = std::chrono::steady_clock::now(); + +	this->elapsed_time = elapsed_time_t{0}; +	this->elapsed_fixed_time = elapsed_time_t{0}; +	this->delta_time = duration_t{0}; +} + +void LoopTimerManager::update() { +	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; + +	if (this->delta_time > this->maximum_delta_time) { +		this->delta_time = this->maximum_delta_time; +	} +	if (this->delta_time > 0s) { +		this->actual_fps = 1.0 / duration_cast<seconds>(this->delta_time).count(); +	} else { +		this->actual_fps = 0; +	} +	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; +} + +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<elapsed_time_t>(this->fixed_delta_time); +} + +void LoopTimerManager::set_target_framerate(unsigned fps) { +	this->target_fps = 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; +} + +unsigned LoopTimerManager::get_fps() const { return this->actual_fps; } + +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() { +	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) { +		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_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); +} + +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 new file mode 100644 index 0000000..91403e4 --- /dev/null +++ b/src/crepe/manager/LoopTimerManager.h @@ -0,0 +1,175 @@ +#pragma once + +#include <chrono> + +#include "Manager.h" + +namespace crepe { + +typedef std::chrono::duration<double> duration_t; +typedef std::chrono::duration<unsigned long long, std::micro> elapsed_time_t; + +/** + * \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: +	/** +	 * \param mediator A reference to a Mediator object used for transfering managers. +	 */ +	LoopTimerManager(Mediator & mediator); +	/** +	 * \brief Get the current delta time for the current frame. +	 *	 +	 * This value represents the estimated frame duration of the current frame. +	 * This value can be used in the frame_update to convert pixel based values to time based values. +	 *  +	 * \return Delta time in seconds since the last frame. +	 */ +	duration_t get_delta_time() const; + +	/** +	 * \brief Get the current elapsed time (total time passed ) +	 * +	 * \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. +	 */ +	elapsed_time_t get_elapsed_time() const; + +	/** +	 * \brief Set the target frames per second (FPS). +	 * +	 * \param fps The desired frames rendered per second. +	 */ +	void set_target_framerate(unsigned fps); + +	/** +	 * \brief Get the current frames per second (FPS). +	 * +	 * \return Current FPS. +	 */ +	unsigned 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. +	 */ +	float 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); + +	/** +	 * \brief Get the fixed delta time in seconds without scaling by the time scale. +	 * +	 * This value is used in the LoopManager to determine how many times  +	 * the fixed_update should be called within a given interval. +	 * +	 * \return The unscaled fixed delta time in seconds. +	 */ +	duration_t get_fixed_delta_time() const; + +	/** +	 * \brief Set the fixed_delta_time in seconds. +	 *  +	 * \param seconds fixed_delta_time in seconds. +	 *  +	 * The fixed_delta_time value is used to determine how many times per second the fixed_update and process_input functions are called. +	 *  +	 */ +	void set_fixed_delta_time(float seconds); + +	/** +	 * \brief Retrieves the scaled fixed delta time in seconds. +	 * +	 * The scaled fixed delta time is the timing value used within the `fixed_update` function.  +	 * It is adjusted by the time_scale to account for any changes in the simulation's  +	 * speed. +	 * +	 * \return The fixed delta time, scaled by the current time scale, in seconds. +	 */ +	duration_t get_scaled_fixed_delta_time() const; + +private: +	//! Friend relation to use start,enforce_frame_rate,get_lag,update,advance_fixed_update. +	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 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. +	 */ +	duration_t 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 Progress the elapsed fixed time by the fixed delta time interval. +	 * +	 * This method advances the game's fixed update loop by adding the fixed_delta_time  +	 * to elapsed_fixed_time, ensuring the fixed update catches up with the elapsed time. +	 */ +	void advance_fixed_elapsed_time(); + +private: +	//! Target frames per second. +	unsigned target_fps = 60; +	//! Actual frames per second. +	unsigned actual_fps = 0; +	//! 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}; +	//! Delta time for the current frame in seconds. +	duration_t delta_time{0.0}; +	//! Target time per frame in seconds +	duration_t frame_target_time{1.0 / target_fps}; +	//! Fixed delta time for fixed updates in seconds. +	duration_t fixed_delta_time{1.0 / 50.0}; +	//! Total elapsed game time in microseconds. +	elapsed_time_t elapsed_time{0}; +	//! Total elapsed time for fixed updates in microseconds. +	elapsed_time_t elapsed_fixed_time{0}; + +	typedef std::chrono::steady_clock::time_point time_point_t; +	//! Time of the last frame. +	time_point_t last_frame_time; +}; + +} // namespace crepe diff --git a/src/crepe/manager/Mediator.h b/src/crepe/manager/Mediator.h index 628154a..a055bb9 100644 --- a/src/crepe/manager/Mediator.h +++ b/src/crepe/manager/Mediator.h @@ -2,13 +2,12 @@  #include "../util/OptionalRef.h" -// TODO: remove these singletons: -#include "EventManager.h" -  namespace crepe {  class ComponentManager;  class SceneManager; +class EventManager; +class LoopTimerManager;  class SaveManager;  class ResourceManager;  class SDLContext; @@ -30,10 +29,10 @@ struct Mediator {  	OptionalRef<SDLContext> sdl_context;  	OptionalRef<ComponentManager> component_manager;  	OptionalRef<SceneManager> scene_manager; +	OptionalRef<EventManager> event_manager; +	OptionalRef<LoopTimerManager> loop_timer;  	OptionalRef<SaveManager> save_manager; -	OptionalRef<EventManager> event_manager = EventManager::get_instance();  	OptionalRef<ResourceManager> resource_manager; -	OptionalRef<LoopTimer> timer;  };  } // namespace crepe diff --git a/src/crepe/manager/SceneManager.cpp b/src/crepe/manager/SceneManager.cpp index 50a9fbb..d4ca90b 100644 --- a/src/crepe/manager/SceneManager.cpp +++ b/src/crepe/manager/SceneManager.cpp @@ -32,4 +32,7 @@ void SceneManager::load_next_scene() {  	// Load the new scene  	scene->load_scene(); + +	//clear the next scene +	next_scene.clear();  } diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index 7f04432..d231c7c 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -1,22 +1,24 @@  #include <algorithm>  #include <cmath> -#include "api/LoopTimer.h"  #include "manager/ComponentManager.h" +#include "manager/LoopTimerManager.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; -	LoopTimer & timer = mediator.timer; +	LoopTimerManager & timer = mediator.loop_timer;  	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 = timer.get_delta_time(); +	duration_t dt = loop_timer.get_delta_time();  	// Loop through all AI components  	for (AI & ai : ai_components) { @@ -43,7 +45,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/crepe/system/AnimatorSystem.cpp b/src/crepe/system/AnimatorSystem.cpp index d61ba35..31eb85c 100644 --- a/src/crepe/system/AnimatorSystem.cpp +++ b/src/crepe/system/AnimatorSystem.cpp @@ -2,7 +2,7 @@  #include "../api/Animator.h"  #include "../manager/ComponentManager.h" -#include "api/LoopTimer.h" +#include "../manager/LoopTimerManager.h"  #include "AnimatorSystem.h" @@ -10,10 +10,10 @@ using namespace crepe;  void AnimatorSystem::update() {  	ComponentManager & mgr = this->mediator.component_manager; -	LoopTimer & timer = this->mediator.timer; +	LoopTimerManager & timer = this->mediator.loop_timer;  	RefVector<Animator> animations = mgr.get_components_by_type<Animator>(); -	double elapsed_time = timer.get_current_time(); +	unsigned long long elapsed_time = timer.get_elapsed_time().count();  	for (Animator & a : animations) {  		if (!a.active) continue; |