diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/crepe/api/Config.h | 2 | ||||
-rw-r--r-- | src/crepe/api/LoopTimer.h | 145 | ||||
-rw-r--r-- | src/crepe/api/Rigidbody.h | 2 | ||||
-rw-r--r-- | src/crepe/system/AISystem.cpp | 2 | ||||
-rw-r--r-- | src/crepe/system/PhysicsSystem.cpp | 119 | ||||
-rw-r--r-- | src/test/PhysicsTest.cpp | 2 |
6 files changed, 206 insertions, 66 deletions
diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 6472270..cd27343 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -53,7 +53,7 @@ struct Config final { * * Gravity value of game. */ - double gravity = 1; + float gravity = 1; } physics; //! default window settings diff --git a/src/crepe/api/LoopTimer.h b/src/crepe/api/LoopTimer.h new file mode 100644 index 0000000..8d0b2f9 --- /dev/null +++ b/src/crepe/api/LoopTimer.h @@ -0,0 +1,145 @@ +#pragma once + +#include <chrono> + +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); + + /** + * \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; + +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 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::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/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 40c6bf1..f641fff 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -79,7 +79,7 @@ public: //! Linear velocity of the object (speed and direction). vec2 linear_velocity; //! Maximum linear velocity of the object. This limits the object's speed. - vec2 max_linear_velocity = {INFINITY, INFINITY}; + float max_linear_velocity = INFINITY; //! Linear velocity coefficient. This scales the object's velocity for adjustment or damping. vec2 linear_velocity_coefficient = {1, 1}; //! \} diff --git a/src/crepe/system/AISystem.cpp b/src/crepe/system/AISystem.cpp index d231c7c..1d8ffb9 100644 --- a/src/crepe/system/AISystem.cpp +++ b/src/crepe/system/AISystem.cpp @@ -146,7 +146,7 @@ vec2 AISystem::arrive(const AI & ai, const Rigidbody & rigidbody, } float speed = distance / ai.arrive_deceleration; - speed = std::min(speed, rigidbody.data.max_linear_velocity.length()); + speed = std::min(speed, rigidbody.data.max_linear_velocity); vec2 desired_velocity = to_target * (speed / distance); return desired_velocity - rigidbody.data.linear_velocity; diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index ebf4439..be768f9 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -11,82 +11,77 @@ using namespace crepe; void PhysicsSystem::update() { + double dt = LoopTimer::get_instance().get_fixed_delta_time(); ComponentManager & mgr = this->mediator.component_manager; RefVector<Rigidbody> rigidbodies = mgr.get_components_by_type<Rigidbody>(); - RefVector<Transform> transforms = mgr.get_components_by_type<Transform>(); + - double gravity = Config::get_instance().physics.gravity; + float gravity = Config::get_instance().physics.gravity; for (Rigidbody & rigidbody : rigidbodies) { if (!rigidbody.active) continue; + Transform & transform = mgr.get_components_by_id<Transform>(rigidbody.game_object_id).front().get(); switch (rigidbody.data.body_type) { case Rigidbody::BodyType::DYNAMIC: - for (Transform & transform : transforms) { - if (transform.game_object_id == rigidbody.game_object_id) { - - // Add gravity - if (rigidbody.data.gravity_scale > 0) { - rigidbody.data.linear_velocity.y - += (rigidbody.data.mass * rigidbody.data.gravity_scale - * gravity); - } - // Add damping - if (rigidbody.data.angular_velocity_coefficient > 0) { - rigidbody.data.angular_velocity - *= rigidbody.data.angular_velocity_coefficient; - } - if (rigidbody.data.linear_velocity_coefficient.x > 0 - && rigidbody.data.linear_velocity_coefficient.y > 0) { - rigidbody.data.linear_velocity - *= rigidbody.data.linear_velocity_coefficient; - } + if (transform.game_object_id == rigidbody.game_object_id) { + // Add gravity + if (rigidbody.data.gravity_scale > 0) { + rigidbody.data.linear_velocity.y + += (rigidbody.data.mass * rigidbody.data.gravity_scale + * gravity * dt); + } + // Add coefficient rotation + if (rigidbody.data.angular_velocity_coefficient > 0) { + rigidbody.data.angular_velocity + *= std::pow(rigidbody.data.angular_velocity_coefficient, dt); + + } - // Max velocity check - if (rigidbody.data.angular_velocity - > rigidbody.data.max_angular_velocity) { - rigidbody.data.angular_velocity - = rigidbody.data.max_angular_velocity; - } else if (rigidbody.data.angular_velocity - < -rigidbody.data.max_angular_velocity) { - rigidbody.data.angular_velocity - = -rigidbody.data.max_angular_velocity; - } + // Add coefficient movement horizontal + if (rigidbody.data.linear_velocity_coefficient.x > 0) + { + rigidbody.data.linear_velocity.x + *= std::pow(rigidbody.data.linear_velocity_coefficient.x, dt); + } - if (rigidbody.data.linear_velocity.x - > rigidbody.data.max_linear_velocity.x) { - rigidbody.data.linear_velocity.x - = rigidbody.data.max_linear_velocity.x; - } else if (rigidbody.data.linear_velocity.x - < -rigidbody.data.max_linear_velocity.x) { - rigidbody.data.linear_velocity.x - = -rigidbody.data.max_linear_velocity.x; - } + // Add coefficient movement horizontal + if (rigidbody.data.linear_velocity_coefficient.y > 0) + { + rigidbody.data.linear_velocity.y + *= std::pow(rigidbody.data.linear_velocity_coefficient.y, dt); + } - if (rigidbody.data.linear_velocity.y - > rigidbody.data.max_linear_velocity.y) { - rigidbody.data.linear_velocity.y - = rigidbody.data.max_linear_velocity.y; - } else if (rigidbody.data.linear_velocity.y - < -rigidbody.data.max_linear_velocity.y) { - rigidbody.data.linear_velocity.y - = -rigidbody.data.max_linear_velocity.y; - } + // Max velocity check + if (rigidbody.data.angular_velocity + > rigidbody.data.max_angular_velocity) { + rigidbody.data.angular_velocity + = rigidbody.data.max_angular_velocity; + } else if (rigidbody.data.angular_velocity + < -rigidbody.data.max_angular_velocity) { + rigidbody.data.angular_velocity + = -rigidbody.data.max_angular_velocity; + } + + // Set max velocity to maximum length + if(rigidbody.data.linear_velocity.length() > rigidbody.data.max_linear_velocity) { + rigidbody.data.linear_velocity.normalize(); + rigidbody.data.linear_velocity *= rigidbody.data.max_linear_velocity; + } - // Move object - if (!rigidbody.data.constraints.rotation) { - transform.rotation += rigidbody.data.angular_velocity; - transform.rotation = std::fmod(transform.rotation, 360.0); - if (transform.rotation < 0) { - transform.rotation += 360.0; - } - } - if (!rigidbody.data.constraints.x) { - transform.position.x += rigidbody.data.linear_velocity.x; - } - if (!rigidbody.data.constraints.y) { - transform.position.y += rigidbody.data.linear_velocity.y; + // Move object + if (!rigidbody.data.constraints.rotation) { + transform.rotation += rigidbody.data.angular_velocity * dt; + transform.rotation = std::fmod(transform.rotation, 360.0); + if (transform.rotation < 0) { + transform.rotation += 360.0; } } + if (!rigidbody.data.constraints.x) { + transform.position.x += rigidbody.data.linear_velocity.x * dt; + } + if (!rigidbody.data.constraints.y) { + transform.position.y += rigidbody.data.linear_velocity.y * dt; + } } break; case Rigidbody::BodyType::KINEMATIC: diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 43d2931..4af34f5 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -27,7 +27,7 @@ public: .mass = 1, .gravity_scale = 1, .body_type = Rigidbody::BodyType::DYNAMIC, - .max_linear_velocity = vec2{10, 10}, + .max_linear_velocity = 10, .max_angular_velocity = 10, .constraints = {0, 0}, }); |