diff options
m--------- | lib/sdl2 | 0 | ||||
m--------- | lib/sdl_image | 0 | ||||
m--------- | lib/sdl_ttf | 0 | ||||
m--------- | lib/soloud | 0 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.cpp | 61 | ||||
-rw-r--r-- | src/crepe/api/LoopManager.h | 66 | ||||
-rw-r--r-- | src/crepe/api/LoopTimer.cpp | 59 | ||||
-rw-r--r-- | src/crepe/api/LoopTimer.h | 81 | ||||
-rw-r--r-- | src/example/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/example/gameLoop.cpp | 8 | ||||
-rw-r--r-- | src/makefile | 5 |
12 files changed, 284 insertions, 1 deletions
diff --git a/lib/sdl2 b/lib/sdl2 -Subproject 9519b9916cd29a14587af0507292f2bd31dd575 +Subproject c98c4fbff6d8f3016a3ce6685bf8f43433c3efc diff --git a/lib/sdl_image b/lib/sdl_image -Subproject abcf63aa71b4e3ac32120fa9870a6500ddcdcc8 +Subproject 56560190a6c5b5740e5afdce747e2a2bfbf16db diff --git a/lib/sdl_ttf b/lib/sdl_ttf -Subproject 4a318f8dfaa1bb6f10e0c5e54052e25d3c7f344 +Subproject a3d0895c1b60c41ff9e85d9203ddd7485c014da diff --git a/lib/soloud b/lib/soloud -Subproject c8e339fdce5c7107bdb3e64bbf707c8fd3449be +Subproject e82fd32c1f62183922f08c14c814a02b58db187 diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 3b20142..e7894d7 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -16,6 +16,8 @@ target_sources(crepe PUBLIC Scene.cpp SceneManager.cpp Vector2.cpp + LoopManager.cpp + LoopTimer.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -38,4 +40,6 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES Metadata.h SceneManager.h SceneManager.hpp + LoopManager.h + LoopTimer.h ) diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp new file mode 100644 index 0000000..746e9ce --- /dev/null +++ b/src/crepe/api/LoopManager.cpp @@ -0,0 +1,61 @@ + + +#include "../system/RenderSystem.h" +#include "../system/ScriptSystem.h" + +#include "LoopManager.h" +#include "LoopTimer.h" + +namespace crepe { + +void LoopManager::process_input() { + SDLContext::get_instance().handle_events(this->gameRunning); +} +void LoopManager::start(){ + this->setup(); + this->loop(); +} +void LoopManager::set_running(bool running) { this->gameRunning = running; } + +void LoopManager::fixed_update() { +} + +void LoopManager::loop() { + LoopTimer & timer = LoopTimer::getInstance(); + timer.start(); + + while (gameRunning) { + 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->gameRunning = true; + LoopTimer::getInstance().start(); + LoopTimer::getInstance().set_fps(60); +} + +void LoopManager::render() { + if (gameRunning) { + RenderSystem::get_instance().update(); + } +} + +void LoopManager::update() { + LoopTimer & timer = LoopTimer::getInstance(); + ScriptSystem::get_instance().update(); +} + +} // namespace crepe diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h new file mode 100644 index 0000000..a5c88c3 --- /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 gameRunning = false; + }; + +} // namespace crepe diff --git a/src/crepe/api/LoopTimer.cpp b/src/crepe/api/LoopTimer.cpp new file mode 100644 index 0000000..5e432fc --- /dev/null +++ b/src/crepe/api/LoopTimer.cpp @@ -0,0 +1,59 @@ + +#include "../facade/SDLContext.h" + +#include "api/LoopTimer.h" + + +using namespace crepe; +LoopTimer::LoopTimer() {} + +LoopTimer & LoopTimer::getInstance() { + 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..584a408 --- /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& getInstance(); + +/** + * \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::api diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index 36f9d4d..751b556 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..f3edbdb --- /dev/null +++ b/src/example/gameLoop.cpp @@ -0,0 +1,8 @@ +#include "crepe/api/LoopManager.h" +using namespace crepe; + +int main(){ + LoopManager loop; + loop.start(); + return 1; +} diff --git a/src/makefile b/src/makefile index b9c44c8..5e525e8 100644 --- a/src/makefile +++ b/src/makefile @@ -94,7 +94,10 @@ LOEK += example/script.cpp LOEK += test/audio.cpp LOEK += test/dummy.cpp JARO += test/PhysicsTest.cpp - +WOUTER += crepe/api/LoopManager.cpp +WOUTER += crepe/api/LoopManager.h +WOUTER += crepe/api/LoopTimer.cpp +WOUTER += crepe/api/LoopTimer.h FMT := $(JARO) #<<< CHANGE THIS TO YOUR NAME FOR STEP 2 format: FORCE clang-tidy -p build/compile_commands.json --fix-errors $(FMT) |