aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/system/ParticleSystem.cpp
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-11-13 19:32:14 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-11-13 19:32:14 +0100
commit56cf219a25e66f38c50a51afd01ed515de149711 (patch)
tree016293d4e13fa2e141a960062e005b608ccecebf /src/crepe/system/ParticleSystem.cpp
parentd69f1642cb397d68d591718f83028e14620ab340 (diff)
parent0b2ca3c323c7f73d031e7014ba0a17dcf0b59751 (diff)
merge `jaro/particle-system-master` into `loek/cleanup` early
Diffstat (limited to 'src/crepe/system/ParticleSystem.cpp')
-rw-r--r--src/crepe/system/ParticleSystem.cpp155
1 files changed, 118 insertions, 37 deletions
diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp
index fe02682..33db52e 100644
--- a/src/crepe/system/ParticleSystem.cpp
+++ b/src/crepe/system/ParticleSystem.cpp
@@ -1,60 +1,141 @@
#include <cmath>
+#include <cstdlib>
#include <ctime>
-#include "../ComponentManager.h"
-#include "../api/ParticleEmitter.h"
+#include "api/ParticleEmitter.h"
+#include "api/Transform.h"
+#include "api/Vector2.h"
+#include "ComponentManager.h"
#include "ParticleSystem.h"
using namespace crepe;
void ParticleSystem::update() {
+ // Get all emitters
ComponentManager & mgr = this->component_manager;
std::vector<std::reference_wrapper<ParticleEmitter>> emitters
= mgr.get_components_by_type<ParticleEmitter>();
- float delta_time = 0.10;
+
for (ParticleEmitter & emitter : emitters) {
- float update_amount = 1 / static_cast<float>(emitter.emission_rate);
- for (float i = 0; i < delta_time; i += update_amount) {
- emit_particle(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);
}
- for (size_t j = 0; j < emitter.particles.size(); j++) {
- if (emitter.particles[j].active) {
- emitter.particles[j].update(delta_time);
+
+ // Update all particles
+ for (Particle & particle : emitter.data.particles) {
+ if (particle.active) {
+ particle.update();
}
}
+
+ // Check if within boundary
+ check_bounds(emitter, transform);
}
+
+ this->update_count = (this->update_count + 1) % this->MAX_UPDATE_COUNT;
}
-void ParticleSystem::emit_particle(ParticleEmitter & emitter) {
- Position initial_position = {emitter.position.x, emitter.position.y};
- float random_angle = 0.0f;
- if (emitter.max_angle < emitter.min_angle) {
- random_angle = ((emitter.min_angle
- + (std::rand()
- % (static_cast<uint32_t>(emitter.max_angle + 360
- - emitter.min_angle + 1))))
- % 360);
- } else {
- random_angle = emitter.min_angle
- + (std::rand()
- % (static_cast<uint32_t>(emitter.max_angle
- - emitter.min_angle + 1)));
- }
- float angle_in_radians = random_angle * (M_PI / 180.0f);
- float random_speed_offset = (static_cast<float>(std::rand()) / RAND_MAX)
- * (2 * emitter.speed_offset)
- - emitter.speed_offset;
- float velocity_x
- = (emitter.speed + random_speed_offset) * std::cos(angle_in_radians);
- float velocity_y
- = (emitter.speed + random_speed_offset) * std::sin(angle_in_radians);
- Position initial_velocity = {velocity_x, velocity_y};
- for (size_t i = 0; i < emitter.particles.size(); i++) {
- if (!emitter.particles[i].active) {
- emitter.particles[i].reset(emitter.end_lifespan, initial_position,
- initial_velocity);
+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 random_angle
+ = generate_random_angle(emitter.data.min_angle, emitter.data.max_angle);
+
+ 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)};
+
+ 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) const {
+ double integer_part = std::floor(emission);
+ double fractional_part = emission - integer_part;
+
+ if (fractional_part > 0) {
+ int denominator = static_cast<int>(1.0 / fractional_part);
+ return (count % denominator == 0) ? 1 : 0;
+ }
+
+ return static_cast<int>(emission);
+}
+
+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;
+
+ 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;
+
+ 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);
+
+ if (!within_bounds) {
+ if (emitter.data.boundary.reset_on_exit) {
+ particle.active = false;
+ } else {
+ particle.velocity = {0, 0};
+ 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));
+ }
+}