diff options
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 60 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.h | 66 | ||||
-rw-r--r-- | src/crepe/api/LoopTimer.cpp | 58 | ||||
-rw-r--r-- | src/crepe/api/LoopTimer.h | 81 | ||||
-rw-r--r-- | src/crepe/facade/SDLContext.cpp | 3 | ||||
-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 | 7 |
9 files changed, 292 insertions, 4 deletions
diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp new file mode 100644 index 0000000..5c79920 --- /dev/null +++ b/src/crepe/api/LoopManager.cpp @@ -0,0 +1,60 @@ + +#include "../system/RenderSystem.h" +#include "../system/ScriptSystem.h" +#include "../facade/SDLContext.h" + +#include "LoopManager.h" +#include "LoopTimer.h" + +namespace crepe { + +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()) { + process_input(); + fixed_update(); + timer.advance_fixed_update(); + } + + update(); + 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 (game_running) { + RenderSystem::get_instance().update(); + } +} + +void LoopManager::update() { + LoopTimer & timer = LoopTimer::get_instance(); +} + +} // namespace crepe diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h new file mode 100644 index 0000000..8899bfd --- /dev/null +++ b/src/crepe/api/LoopManager.h @@ -0,0 +1,66 @@ +#pragma once + +namespace crepe { + +class LoopManager { + public: + void start(); + + 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; + }; + +} // namespace crepe diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp new file mode 100644 index 0000000..98ce08d --- /dev/null +++ b/src/crepe/api/LoopTimer.cpp @@ -0,0 +1,58 @@ + +#include "../facade/SDLContext.h" + +#include "LoopTimer.h" + +using namespace crepe; +LoopTimer::LoopTimer() {} + +LoopTimer & LoopTimer::get_instance() { + static LoopTimer instance; + return instance; +} + +void LoopTimer::start() { + last_frame_time = SDLContext::get_instance().get_ticks(); + elapsed_time = 0; + elapsed_fixed_time = 0; + delta_time = 0; +} + +void LoopTimer::update() { + uint64_t current_frame_time = SDLContext::get_instance().get_ticks(); + delta_time = (current_frame_time - last_frame_time) / 1000.0; + + if (delta_time > maximum_delta_time) { + delta_time = maximum_delta_time; + } + delta_time = game_scale; + elapsed_time += delta_time; + last_frame_time = current_frame_time; +} + +double LoopTimer::get_delta_time() const { return delta_time; } +int LoopTimer::get_current_time() const { return elapsed_time; } + +void LoopTimer::advance_fixed_update() { elapsed_fixed_time += fixed_delta_time; } + +double LoopTimer::get_fixed_delta_time() const { return fixed_delta_time; } + +void LoopTimer::set_fps(int fps) { + this->fps = fps; + frame_target_time = 1.0 / fps; +} + +int LoopTimer::get_fps() const { return fps; } +void LoopTimer::set_game_scale(double value) { game_scale = value; }; +double LoopTimer::get_game_scale() const { return game_scale; } +void LoopTimer::enforce_frame_rate() { + uint64_t current_frame_time = SDLContext::get_instance().get_ticks(); + double frame_duration = (current_frame_time - last_frame_time) / 1000.0; + + if (frame_duration < frame_target_time) { + uint32_t delay_time + = (uint32_t) ((frame_target_time - frame_duration) / 1000.0); + SDLContext::get_instance().delay(delay_time); + } +} +double LoopTimer::get_lag() const { return elapsed_time - elapsed_fixed_time; } diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h new file mode 100644 index 0000000..5b7d3f2 --- /dev/null +++ b/src/crepe/api/LoopTimer.h @@ -0,0 +1,81 @@ +#pragma once + +#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 the real-world elapsed time. + * It is the cumulative sum of each frame's delta time. + * + * \return Elapsed game time in milliseconds. + */ +int get_current_time() const; + +/** + * \brief Set the target frames per second (FPS). + * + * \param fps The number of frames that should be 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; +void start(); +void enforce_frame_rate(); +double get_fixed_delta_time() const; +double get_lag() const; +LoopTimer(); +void update(); +void advance_fixed_update(); +private: +int fps = 50; ///< Current frames per second +double game_scale = 1; ///< Current game scale +double maximum_delta_time = 0.25; ///< Maximum delta time to avoid large jumps +double delta_time = 0; ///< Delta time for the current frame +double frame_target_time = 1.0 / fps; ///< Target time per frame in seconds +double fixed_delta_time = 0.02; ///< Fixed delta time for fixed updates +double elapsed_time = 0; ///< Total elapsed game time +double elapsed_fixed_time = 0; ///< Total elapsed time for fixed updates +uint64_t last_frame_time = 0; ///< Time of the last frame +}; + +} // namespace crepe diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index c4c96e2..17ced0c 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -191,3 +191,6 @@ 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..6c57ef9 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -58,13 +58,22 @@ private: private: //! Will only use get_ticks friend class AnimatorSystem; - + 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: /** * \brief Constructs an SDLContext instance. 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..6cd0301 --- /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..ce5a29f 100644 --- a/src/makefile +++ b/src/makefile @@ -94,8 +94,11 @@ 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 +WOUTER += crepe/api/LoopManager.h +WOUTER += crepe/api/LoopManager.cpp +WOUTER += crepe/api/LoopTimer.h +WOUTER += crepe/api/LoopTimer.cpp +FMT := $(WOUTER) #<<< CHANGE THIS TO YOUR NAME FOR STEP 2 format: FORCE clang-tidy -p build/compile_commands.json --fix-errors $(FMT) |