diff options
-rw-r--r-- | src/crepe/Particle.h | 1 | ||||
-rw-r--r-- | src/crepe/system/ParticleSystem.cpp | 157 | ||||
-rw-r--r-- | src/crepe/system/ParticleSystem.h | 61 |
3 files changed, 115 insertions, 104 deletions
diff --git a/src/crepe/Particle.h b/src/crepe/Particle.h index 77c3ea3..88a015d 100644 --- a/src/crepe/Particle.h +++ b/src/crepe/Particle.h @@ -14,6 +14,7 @@ namespace crepe { * to simulate movement and can also be reset or stopped. */ class Particle { + // TODO: add friend particleSsytem and rendersystem. Unit test will fail. public: //! Position of the particle in 2D space. Vector2 position; diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index e6dc670..a0b1e55 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -13,151 +13,112 @@ using namespace crepe; ParticleSystem::ParticleSystem() {} void ParticleSystem::update() { - // Get all emitters ComponentManager & mgr = ComponentManager::get_instance(); - std::vector<std::reference_wrapper<ParticleEmitter>> emitters - = mgr.get_components_by_type<ParticleEmitter>(); + std::vector<std::reference_wrapper<ParticleEmitter>> emitters = mgr.get_components_by_type<ParticleEmitter>(); for (ParticleEmitter & emitter : emitters) { - - // Get transform linked to emitter + // Get transform linked to emitter const Transform& transform = mgr.get_components_by_id<Transform>(emitter.game_object_id).front().get(); - // Emit particles based on emission_rate - int updates = calculate_update(this->update_count,emitter.data.emission_rate); - for (size_t i = 0; i < updates; i++) - { - emit_particle(emitter,transform); + int updates = calculate_update(this->update_count, emitter.data.emission_rate); + for (size_t i = 0; i < updates; i++) { + emit_particle(emitter, transform); } - + // Update all particles - for (size_t j = 0; j < emitter.data.particles.size(); j++) { - if (emitter.data.particles[j].active) { - emitter.data.particles[j].update(); + for (Particle& particle : emitter.data.particles) { + if (particle.active) { + particle.update(); } } - // Check if within boundary - check_bounds(emitter,transform); + // Check if within boundary + check_bounds(emitter, transform); } - update_count++; - if(update_count == MAX_UPDATE_COUNT) update_count = 0; + update_count = (update_count + 1) % MAX_UPDATE_COUNT; } -void ParticleSystem::emit_particle(ParticleEmitter & emitter,const Transform& transform) { +void ParticleSystem::emit_particle(ParticleEmitter & emitter, const Transform& transform) { constexpr double DEG_TO_RAD = M_PI / 180.0; Vector2 initial_position = emitter.data.position + transform.position; - double min_angle = emitter.data.min_angle; - double max_angle = emitter.data.max_angle; - double random_angle; - if(min_angle == max_angle){ - random_angle = min_angle; - } - else if (min_angle <= max_angle) { - // Standard range (e.g., 10 to 20 degrees) - double angle_offset = max_angle - min_angle; - random_angle = min_angle + static_cast<double>(std::rand() % static_cast<uint32_t>(angle_offset)); - } else { - // Wrap-around range (e.g., 350 to 10 degrees) - double angle_offset = (360 - min_angle) + max_angle; - random_angle = min_angle + static_cast<double>(std::rand() % static_cast<uint32_t>(angle_offset)); - - // Wrap around to keep random_angle within 0-360 degrees - if (random_angle >= 360) { - random_angle -= 360; - } - } + double random_angle = generate_random_angle(emitter.data.min_angle, emitter.data.max_angle); - // Generate a random speed between min_speed and max_speed - double speed_offset = emitter.data.max_speed - emitter.data.min_speed; - double random_speed = 0.0; - if(emitter.data.max_speed == emitter.data.min_speed) - { - random_speed = emitter.data.min_speed; - } - else { - random_speed = emitter.data.min_speed + static_cast<double>(std::rand() % static_cast<uint32_t>(speed_offset)); - } - - // Convert random_angle to radians + double random_speed = generate_random_speed(emitter.data.min_speed, emitter.data.max_speed); double angle_radians = random_angle * DEG_TO_RAD; Vector2 velocity = { - random_speed * std::cos(angle_radians), - random_speed * std::sin(angle_radians) - }; + random_speed * std::cos(angle_radians), + random_speed * std::sin(angle_radians) + }; - - for (size_t i = 0; i < emitter.data.particles.size(); i++) { - if (!emitter.data.particles[i].active) { - emitter.data.particles[i].reset(emitter.data.end_lifespan, initial_position,velocity,random_angle); + for (Particle& particle : emitter.data.particles) { + if (!particle.active) { + particle.reset(emitter.data.end_lifespan, initial_position, velocity, random_angle); break; } } } -int ParticleSystem::calculate_update(int count, double emission) { - - //get interger part of the emission +int ParticleSystem::calculate_update(int count, double emission) const { double integer_part = std::floor(emission); - - // Get the fractional part of the emission double fractional_part = emission - integer_part; - // Convert the fractional part to a denominator value - int denominator = static_cast<int>(1.0 / fractional_part); - - // For emissions like 0.01, 0.1, 0.5, etc., calculate the update frequency if (fractional_part > 0) { - // Calculate how often the update should be triggered based on the fractional part - if (count % denominator == 0) { - return 1; - } else { - return 0; - } + int denominator = static_cast<int>(1.0 / fractional_part); + return (count % denominator == 0) ? 1 : 0; } - - // For integer emissions, return the emission directly + return static_cast<int>(emission); } -void ParticleSystem::check_bounds(ParticleEmitter & emitter,const Transform& transform) -{ +void ParticleSystem::check_bounds(ParticleEmitter & emitter, const Transform& transform) { Vector2 offset = emitter.data.boundary.offset + transform.position + emitter.data.position; double half_width = emitter.data.boundary.width / 2.0; double half_height = emitter.data.boundary.height / 2.0; - // Define boundary edges - const double left = offset.x - half_width; - const double right = offset.x + half_width; - const double top = offset.y - half_height; - const double bottom = offset.y + half_height; + const double LEFT = offset.x - half_width; + const double RIGHT = offset.x + half_width; + const double TOP = offset.y - half_height; + const double BOTTOM = offset.y + half_height; - std::vector<Particle>& particles = emitter.data.particles; - for (Particle& particle : particles) - { + for (Particle& particle : emitter.data.particles) { const Vector2& position = particle.position; + bool within_bounds = (position.x >= LEFT && position.x <= RIGHT && position.y >= TOP && position.y <= BOTTOM); - // Check if particle is within bounds - bool within_bounds = (position.x >= left && position.x <= right && position.y >= top && position.y <= bottom); - if (!within_bounds) - { - if (emitter.data.boundary.reset_on_exit) - { + if (!within_bounds) { + if (emitter.data.boundary.reset_on_exit) { particle.active = false; - } - else - { + } else { particle.velocity = {0, 0}; - if (particle.position.x < left) particle.position.x = left; - else if (particle.position.x > right) particle.position.x = right; - if (particle.position.y < bottom) particle.position.y = bottom; - else if (particle.position.y > top) particle.position.y = top; + if (position.x < LEFT) particle.position.x = LEFT; + else if (position.x > RIGHT) particle.position.x = RIGHT; + if (position.y < TOP) particle.position.y = TOP; + else if (position.y > BOTTOM) particle.position.y = BOTTOM; } } } } + +double ParticleSystem::generate_random_angle(double min_angle, double max_angle) const { + if (min_angle == max_angle) { + return min_angle; + } else if (min_angle < max_angle) { + return min_angle + static_cast<double>(std::rand() % static_cast<int>(max_angle - min_angle)); + } else { + double angle_offset = (360 - min_angle) + max_angle; + double random_angle = min_angle + static_cast<double>(std::rand() % static_cast<int>(angle_offset)); + return (random_angle >= 360) ? random_angle - 360 : random_angle; + } +} + +double ParticleSystem::generate_random_speed(double min_speed, double max_speed) const { + if (min_speed == max_speed) { + return min_speed; + } else { + return min_speed + static_cast<double>(std::rand() % static_cast<int>(max_speed - min_speed)); + } +} diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h index 3b9cb54..df89ed9 100644 --- a/src/crepe/system/ParticleSystem.h +++ b/src/crepe/system/ParticleSystem.h @@ -4,21 +4,70 @@ namespace crepe { +/** + * \brief ParticleSystem class responsible for managing particle emission, updates, and bounds checking. + */ class ParticleSystem { public: + /** + * \brief Default constructor. + */ ParticleSystem(); + + /** + * \brief Updates all particle emitters by emitting particles, updating particle states, and checking bounds. + */ void update(); private: - void emit_particle(ParticleEmitter & emitter,const Transform& transform); - int calculate_update(int count, double emission); - void check_bounds(ParticleEmitter & emitter,const Transform& transform); + /** + * \brief Emits a particle from the specified emitter based on its emission properties. + * + * \param emitter Reference to the ParticleEmitter. + * \param transform Const reference to the Transform component associated with the emitter. + */ + void emit_particle(ParticleEmitter & emitter, const Transform& transform); + + /** + * \brief Calculates the number of times particles should be emitted based on emission rate and update count. + * + * \param count Current update count. + * \param emission Emission rate. + * \return The number of particles to emit. + */ + int calculate_update(int count, double emission) const; + + /** + * \brief Checks whether particles are within the emitter’s boundary, resets or stops particles if they exit. + * + * \param emitter Reference to the ParticleEmitter. + * \param transform Const reference to the Transform component associated with the emitter. + */ + void check_bounds(ParticleEmitter & emitter, const Transform& transform); + + /** + * \brief Generates a random angle for particle emission within the specified range. + * + * \param min_angle Minimum emission angle in degrees. + * \param max_angle Maximum emission angle in degrees. + * \return Random angle in degrees. + */ + double generate_random_angle(double min_angle, double max_angle) const; + + /** + * \brief Generates a random speed for particle emission within the specified range. + * + * \param min_speed Minimum emission speed. + * \param max_speed Maximum emission speed. + * \return Random speed. + */ + double generate_random_speed(double min_speed, double max_speed) const; private: - //! counter to count updates to determine how many times emit_particle is called. + //! Counter to count updates to determine how many times emit_particle is called. uint32_t update_count = 0; - //! determines the lowest amount of emissionrate (1000 = 0.001 = 1 particle per 1000 updates). - const uint32_t MAX_UPDATE_COUNT = 100; + //! Determines the lowest amount of emission rate (1000 = 0.001 = 1 particle per 1000 updates). + static constexpr uint32_t MAX_UPDATE_COUNT = 100; }; } // namespace crepe |