diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.cpp | 55 | ||||
| -rw-r--r-- | src/crepe/api/LoopManager.h | 79 | ||||
| -rw-r--r-- | src/crepe/api/LoopTimer.cpp | 86 | ||||
| -rw-r--r-- | src/crepe/api/LoopTimer.h | 147 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.cpp | 1 | ||||
| -rw-r--r-- | src/crepe/facade/SDLContext.h | 13 | ||||
| -rw-r--r-- | src/example/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/example/gameloop.cpp | 7 | ||||
| -rw-r--r-- | src/makefile | 5 | 
10 files changed, 394 insertions, 4 deletions
| diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 87cbb09..85696c4 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -18,6 +18,8 @@ target_sources(crepe PUBLIC  	Vector2.cpp  	Camera.cpp  	Animator.cpp +	LoopManager.cpp +	LoopTimer.cpp  )  target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -42,4 +44,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES  	SceneManager.hpp  	Camera.h  	Animator.h +	LoopManager.h +	LoopTimer.h  ) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp new file mode 100644 index 0000000..2e9823f --- /dev/null +++ b/src/crepe/api/LoopManager.cpp @@ -0,0 +1,55 @@ + +#include "../facade/SDLContext.h" +#include "../system/RenderSystem.h" +#include "../system/ScriptSystem.h" + +#include "LoopManager.h" +#include "LoopTimer.h" + +using namespace crepe; + +LoopManager::LoopManager() {} +void LoopManager::process_input() { +	SDLContext::get_instance().handle_events(this->game_running); +} +void LoopManager::start() { +	this->setup(); +	this->loop(); +} +void LoopManager::set_running(bool running) { this->game_running = running; } + +void LoopManager::fixed_update() {} + +void LoopManager::loop() { +	LoopTimer & timer = LoopTimer::get_instance(); +	timer.start(); + +	while (game_running) { +		timer.update(); + +		while (timer.get_lag() >= timer.get_fixed_delta_time()) { +			this->process_input(); +			this->fixed_update(); +			timer.advance_fixed_update(); +		} + +		this->update(); +		this->render(); + +		timer.enforce_frame_rate(); +	} +} + +void LoopManager::setup() { +	this->game_running = true; +	LoopTimer::get_instance().start(); +	LoopTimer::get_instance().set_fps(60); +} + +void LoopManager::render() { +	if (this->game_running) { +		RenderSystem::get_instance().update(); +	} +} + +void LoopManager::update() { LoopTimer & timer = LoopTimer::get_instance(); } diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h new file mode 100644 index 0000000..2f03193 --- /dev/null +++ b/src/crepe/api/LoopManager.h @@ -0,0 +1,79 @@ +#pragma once + +#include <memory> + +class RenderSystem; +class SDLContext; +class LoopTimer; +class ScriptSystem; +class SoundSystem; +class ParticleSystem; +class PhysicsSystem; +class AnimatorSystem; +class CollisionSystem; +namespace crepe { + +class LoopManager { +public: +	void start(); +	LoopManager(); + +private: +	/** +	 * \brief Setup function for one-time initialization. +	 * +	 * This function initializes necessary components for the game. +	 */ +	void setup(); +	/** +	 * \brief Main game loop function. +	 * +	 * This function runs the main loop, handling game updates and rendering. +	 */ +	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(); + +	/** +	 * \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(); + +	bool game_running = false; +	//#TODO add system instances +}; + +} // namespace crepe diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp new file mode 100644 index 0000000..8f09e41 --- /dev/null +++ b/src/crepe/api/LoopTimer.cpp @@ -0,0 +1,86 @@ +#include <chrono> + +#include "../facade/SDLContext.h" +#include "../util/log.h" + +#include "LoopTimer.h" + +using namespace crepe; + +LoopTimer::LoopTimer() { dbg_trace(); } + +LoopTimer & LoopTimer::get_instance() { +	static LoopTimer instance; +	return instance; +} + +void LoopTimer::start() { +	this->last_frame_time = std::chrono::steady_clock::now(); +	this->elapsed_time = std::chrono::milliseconds(0); +	this->elapsed_fixed_time = std::chrono::milliseconds(0); +	this->delta_time = std::chrono::milliseconds(0); +} + +void LoopTimer::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->delta_time *= this->game_scale; +	this->elapsed_time += this->delta_time; +	this->last_frame_time = current_frame_time; +} + +double LoopTimer::get_delta_time() const { return this->delta_time.count(); } + +double LoopTimer::get_current_time() const { +	return this->elapsed_time.count(); +} + +void LoopTimer::advance_fixed_update() { +	this->elapsed_fixed_time += this->fixed_delta_time; +} + +double LoopTimer::get_fixed_delta_time() const { +	return this->fixed_delta_time.count(); +} + +void LoopTimer::set_fps(int fps) { +	this->fps = fps; +	// target time per frame in seconds +	this->frame_target_time = std::chrono::seconds(1) / fps; +} + +int LoopTimer::get_fps() const { return this->fps; } + +void LoopTimer::set_game_scale(double value) { this->game_scale = value; } + +double LoopTimer::get_game_scale() const { return this->game_scale; } +void LoopTimer::enforce_frame_rate() { +	std::chrono::steady_clock::time_point current_frame_time +		= std::chrono::steady_clock::now(); +	std::chrono::milliseconds frame_duration +		= std::chrono::duration_cast<std::chrono::milliseconds>( +			current_frame_time - this->last_frame_time); + +	if (frame_duration < this->frame_target_time) { +		std::chrono::milliseconds delay_time +			= std::chrono::duration_cast<std::chrono::milliseconds>( +				this->frame_target_time - frame_duration); +		if (delay_time.count() > 0) { +			SDLContext::get_instance().delay(delay_time.count()); +		} +	} + +	this->last_frame_time = current_frame_time; +} + +double LoopTimer::get_lag() const { +	return (this->elapsed_time - this->elapsed_fixed_time).count(); +} diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h new file mode 100644 index 0000000..85687be --- /dev/null +++ b/src/crepe/api/LoopTimer.h @@ -0,0 +1,147 @@ +#pragma once + +#include <chrono> +#include <cstdint> + +namespace crepe { + +class LoopTimer { +public: +	/** +     * \brief Get the singleton instance of LoopTimer. +     * +     * \return A reference to the LoopTimer instance. +     */ +	static LoopTimer & get_instance(); + +	/** +     * \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(); + +	/** +     * \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::seconds(1) / fps; +	//! Fixed delta time for fixed updates in seconds +	std::chrono::duration<double> fixed_delta_time +		= std::chrono::seconds(1) / 50; +	//! 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 c4c96e2..39d0d4d 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -191,3 +191,4 @@ int SDLContext::get_height(const Texture & ctx) const {  	SDL_QueryTexture(ctx.texture.get(), NULL, NULL, NULL, &h);  	return h;  } +void SDLContext::delay(int ms) const { SDL_Delay(ms); } diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index e358c21..536dec5 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -58,12 +58,23 @@ private:  private:  	//! Will only use get_ticks  	friend class AnimatorSystem; - +	//! Will only use delay +	friend class LoopTimer;  	/**  	 * \brief Gets the current SDL ticks since the program started.  	 * \return Current ticks in milliseconds as a constant uint64_t.  	 */  	uint64_t get_ticks() const; +	/** +	 * \brief Pauses the execution for a specified duration. +	 * +	 * This function uses SDL's delay function to halt the program execution +	 * for a given number of milliseconds, allowing for frame rate control +	 * or other timing-related functionality. +	 * +	 * \param ms Duration of the delay in milliseconds. +	 */ +	void delay(int ms) const;  private:  	/** diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 36f9d4d..c8a4b85 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -28,4 +28,5 @@ add_example(proxy)  add_example(db)  add_example(ecs)  add_example(scene_manager) +add_example(gameloop) diff --git a/src/example/gameloop.cpp b/src/example/gameloop.cpp new file mode 100644 index 0000000..a676f20 --- /dev/null +++ b/src/example/gameloop.cpp @@ -0,0 +1,7 @@ +#include "crepe/api/LoopManager.h" +using namespace crepe; +int main() { +	LoopManager gameloop; +	gameloop.start(); +	return 1; +} diff --git a/src/makefile b/src/makefile index b9c44c8..bd05b2e 100644 --- a/src/makefile +++ b/src/makefile @@ -94,11 +94,10 @@ LOEK += example/script.cpp  LOEK += test/audio.cpp  LOEK += test/dummy.cpp  JARO += test/PhysicsTest.cpp - -FMT := $(JARO) #<<< CHANGE THIS TO YOUR NAME FOR STEP 2 +FMT := $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp')  format: FORCE  	clang-tidy -p build/compile_commands.json --fix-errors $(FMT) -# FMT += $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') +# FMT := $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp')  # TODO: re-enable linter after all corrections |