diff options
Diffstat (limited to 'src/crepe/api')
-rw-r--r-- | src/crepe/api/Animator.cpp | 5 | ||||
-rw-r--r-- | src/crepe/api/AssetManager.h | 36 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/crepe/api/Camera.cpp | 3 | ||||
-rw-r--r-- | src/crepe/api/CircleCollider.h | 7 | ||||
-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/api/Metadata.cpp | 4 | ||||
-rw-r--r-- | src/crepe/api/ParticleEmitter.cpp | 36 | ||||
-rw-r--r-- | src/crepe/api/ParticleEmitter.h | 99 | ||||
-rw-r--r-- | src/crepe/api/Rigidbody.cpp | 3 | ||||
-rw-r--r-- | src/crepe/api/Sprite.cpp | 5 | ||||
-rw-r--r-- | src/crepe/api/Transform.cpp | 5 |
15 files changed, 513 insertions, 67 deletions
diff --git a/src/crepe/api/Animator.cpp b/src/crepe/api/Animator.cpp index 8b396af..58fee2a 100644 --- a/src/crepe/api/Animator.cpp +++ b/src/crepe/api/Animator.cpp @@ -10,7 +10,10 @@ using namespace crepe; Animator::Animator(uint32_t id, Sprite & ss, int row, int col, int col_animator) - : Component(id), spritesheet(ss), row(row), col(col) { + : Component(id), + spritesheet(ss), + row(row), + col(col) { dbg_trace(); animator_rect = spritesheet.sprite_rect; diff --git a/src/crepe/api/AssetManager.h b/src/crepe/api/AssetManager.h index fefbed9..86a9902 100644 --- a/src/crepe/api/AssetManager.h +++ b/src/crepe/api/AssetManager.h @@ -7,9 +7,19 @@ namespace crepe { +/** + * \brief The AssetManager is responsible for storing and managing assets over + * multiple scenes. + * + * The AssetManager ensures that assets are loaded once and can be accessed + * across different scenes. It caches assets to avoid reloading them every time + * a scene is loaded. Assets are retained in memory until the AssetManager is + * destroyed, at which point the cached assets are cleared. + */ class AssetManager { private: + //! A cache that holds all the assets, accessible by their file path, over multiple scenes. std::unordered_map<std::string, std::any> asset_cache; private: @@ -22,12 +32,32 @@ public: AssetManager & operator=(const AssetManager &) = delete; AssetManager & operator=(AssetManager &&) = delete; + /** + * \brief Retrieves the singleton instance of the AssetManager. + * + * \return A reference to the single instance of the AssetManager. + */ static AssetManager & get_instance(); public: - template <typename asset> - std::shared_ptr<asset> cache(const std::string & file_path, - bool reload = false); + /** + * \brief Caches an asset by loading it from the given file path. + * + * \param file_path The path to the asset file to load. + * \param reload If true, the asset will be reloaded from the file, even if + * it is already cached. + * \tparam T The type of asset to cache (e.g., texture, sound, etc.). + * + * \return A shared pointer to the cached asset. + * + * This template function caches the asset at the given file path. If the + * asset is already cached and `reload` is false, the existing cached version + * will be returned. Otherwise, the asset will be reloaded and added to the + * cache. + */ + template <typename T> + std::shared_ptr<T> cache(const std::string & file_path, + bool reload = false); }; } // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 6915074..de1b4b3 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -18,8 +18,13 @@ target_sources(crepe PUBLIC Vector2.cpp Camera.cpp Animator.cpp +<<<<<<< HEAD BoxCollider.cpp CircleCollider.cpp +======= + LoopManager.cpp + LoopTimer.cpp +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -44,6 +49,11 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SceneManager.hpp Camera.h Animator.h +<<<<<<< HEAD BoxCollider.h CircleCollider.h +======= + LoopManager.h + LoopTimer.h +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 ) diff --git a/src/crepe/api/Camera.cpp b/src/crepe/api/Camera.cpp index 820a6a8..6355a03 100644 --- a/src/crepe/api/Camera.cpp +++ b/src/crepe/api/Camera.cpp @@ -10,7 +10,8 @@ using namespace crepe; Camera::Camera(uint32_t id, const Color & bg_color) - : Component(id), bg_color(bg_color) { + : Component(id), + bg_color(bg_color) { dbg_trace(); } diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index 29a9c1e..e4f0452 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -8,8 +8,15 @@ namespace crepe { class CircleCollider : public Collider { public: +<<<<<<< HEAD CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius); double radius; +======= + CircleCollider(game_object_id_t game_object_id, int radius) + : Collider(game_object_id), + radius(radius) {} + int radius; +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 }; } // namespace crepe 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/api/Metadata.cpp b/src/crepe/api/Metadata.cpp index 76f11d7..d421de5 100644 --- a/src/crepe/api/Metadata.cpp +++ b/src/crepe/api/Metadata.cpp @@ -4,4 +4,6 @@ using namespace crepe; using namespace std; Metadata::Metadata(game_object_id_t id, const string & name, const string & tag) - : Component(id), name(name), tag(tag) {} + : Component(id), + name(name), + tag(tag) {} diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp index 3b2e2f2..35f960d 100644 --- a/src/crepe/api/ParticleEmitter.cpp +++ b/src/crepe/api/ParticleEmitter.cpp @@ -1,36 +1,12 @@ -#include <ctime> -#include <iostream> - -#include "Particle.h" #include "ParticleEmitter.h" using namespace crepe; -ParticleEmitter::ParticleEmitter(game_object_id_t id, uint32_t max_particles, - uint32_t emission_rate, uint32_t speed, - uint32_t speed_offset, uint32_t angle, - uint32_t angleOffset, float begin_lifespan, - float end_lifespan) - : Component(id), max_particles(max_particles), emission_rate(emission_rate), - speed(speed), speed_offset(speed_offset), position{0, 0}, - begin_lifespan(begin_lifespan), end_lifespan(end_lifespan) { - std::srand( - static_cast<uint32_t>(std::time(nullptr))); // initialize random seed - std::cout << "Create emitter" << std::endl; - // FIXME: Why do these expressions start with `360 +`, only to be `% 360`'d - // right after? This does not make any sense to me. - min_angle = (360 + angle - (angleOffset % 360)) % 360; - max_angle = (360 + angle + (angleOffset % 360)) % 360; - position.x = 400; // FIXME: what are these magic values? - position.y = 400; - for (size_t i = 0; i < max_particles; i++) { - this->particles.emplace_back(); - } -} - -ParticleEmitter::~ParticleEmitter() { - std::vector<Particle>::iterator it = this->particles.begin(); - while (it != this->particles.end()) { - it = this->particles.erase(it); +ParticleEmitter::ParticleEmitter(game_object_id_t game_object_id, + const Data & data) + : Component(game_object_id), + data(data) { + for (size_t i = 0; i < this->data.max_particles; i++) { + this->data.particles.emplace_back(); } } diff --git a/src/crepe/api/ParticleEmitter.h b/src/crepe/api/ParticleEmitter.h index 5939723..a9e872f 100644 --- a/src/crepe/api/ParticleEmitter.h +++ b/src/crepe/api/ParticleEmitter.h @@ -1,42 +1,85 @@ #pragma once -#include <cstdint> #include <vector> #include "Component.h" #include "Particle.h" +#include "Vector2.h" namespace crepe { +class Sprite; + +/** + * \brief Data holder for particle emission parameters. + * + * The ParticleEmitter class stores configuration data for particle properties, + * defining the characteristics and boundaries of particle emissions. + */ class ParticleEmitter : public Component { public: - ParticleEmitter(game_object_id_t id, uint32_t max_particles, - uint32_t emission_rate, uint32_t speed, - uint32_t speed_offset, uint32_t angle, uint32_t angleOffset, - float begin_lifespan, float end_lifespan); - ~ParticleEmitter(); - - //! position of the emitter - Position position; - //! maximum number of particles - uint32_t max_particles; - //! rate of particle emission - uint32_t emission_rate; - //! base speed of the particles - uint32_t speed; - //! offset for random speed variation - uint32_t speed_offset; - //! min angle of particle emission - uint32_t min_angle; - //! max angle of particle emission - uint32_t max_angle; - //! begin Lifespan of particle (only visual) - float begin_lifespan; - //! begin Lifespan of particle - float end_lifespan; - - //! collection of particles - std::vector<Particle> particles; + /** + * \brief Defines the boundary within which particles are constrained. + * + * This structure specifies the boundary's size and offset, as well as the + * behavior of particles upon reaching the boundary limits. + */ + struct Boundary { + //! boundary width (midpoint is emitter location) + double width = 0.0; + //! boundary height (midpoint is emitter location) + double height = 0.0; + //! boundary offset from particle emitter location + Vector2 offset; + //! reset on exit or stop velocity and set max postion + bool reset_on_exit = false; + }; + + /** + * \brief Holds parameters that control particle emission. + * + * Contains settings for the emitter’s position, particle speed, angle, lifespan, + * boundary, and the sprite used for rendering particles. + */ + struct Data { + //! position of the emitter + Vector2 position; + //! maximum number of particles + const unsigned int max_particles = 0; + //! rate of particle emission per update (Lowest value = 0.001 any lower is ignored) + double emission_rate = 0; + //! min speed of the particles + double min_speed = 0; + //! min speed of the particles + double max_speed = 0; + //! min angle of particle emission + double min_angle = 0; + //! max angle of particle emission + double max_angle = 0; + //! begin Lifespan of particle (only visual) + double begin_lifespan = 0.0; + //! end Lifespan of particle + double end_lifespan = 0.0; + //! force over time (physics) + Vector2 force_over_time; + //! particle boundary + Boundary boundary; + //! collection of particles + std::vector<Particle> particles; + //! sprite reference + const Sprite & sprite; + }; + +public: + /** + * \param game_object_id Identifier for the game object using this emitter. + * \param data Configuration data defining particle properties. + */ + ParticleEmitter(game_object_id_t game_object_id, const Data & data); + +public: + //! Configuration data for particle emission settings. + Data data; }; } // namespace crepe diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp index cbf1325..3bf1c5b 100644 --- a/src/crepe/api/Rigidbody.cpp +++ b/src/crepe/api/Rigidbody.cpp @@ -3,7 +3,8 @@ using namespace crepe; crepe::Rigidbody::Rigidbody(uint32_t game_object_id, const Data & data) - : Component(game_object_id), data(data) {} + : Component(game_object_id), + data(data) {} void crepe::Rigidbody::add_force_linear(const Vector2 & force) { this->data.linear_velocity += force; diff --git a/src/crepe/api/Sprite.cpp b/src/crepe/api/Sprite.cpp index f9cd761..6f0433f 100644 --- a/src/crepe/api/Sprite.cpp +++ b/src/crepe/api/Sprite.cpp @@ -12,7 +12,10 @@ using namespace crepe; Sprite::Sprite(game_object_id_t id, const shared_ptr<Texture> image, const Color & color, const FlipSettings & flip) - : Component(id), color(color), flip(flip), sprite_image(image) { + : Component(id), + color(color), + flip(flip), + sprite_image(image) { dbg_trace(); this->sprite_rect.w = sprite_image->get_width(); diff --git a/src/crepe/api/Transform.cpp b/src/crepe/api/Transform.cpp index a244bc5..e401120 100644 --- a/src/crepe/api/Transform.cpp +++ b/src/crepe/api/Transform.cpp @@ -6,6 +6,9 @@ using namespace crepe; Transform::Transform(game_object_id_t id, const Vector2 & point, double rotation, double scale) - : Component(id), position(point), rotation(rotation), scale(scale) { + : Component(id), + position(point), + rotation(rotation), + scale(scale) { dbg_trace(); } |