aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/crepe/Particle.h43
-rw-r--r--src/crepe/api/ParticleEmitter.cpp2
-rw-r--r--src/crepe/api/ParticleEmitter.h45
-rw-r--r--src/crepe/system/ParticleSystem.cpp6
-rw-r--r--src/example/particles.cpp1
-rw-r--r--src/test/CMakeLists.txt3
-rw-r--r--src/test/ParticleTest.cpp86
7 files changed, 169 insertions, 17 deletions
diff --git a/src/crepe/Particle.h b/src/crepe/Particle.h
index f52196c..77c3ea3 100644
--- a/src/crepe/Particle.h
+++ b/src/crepe/Particle.h
@@ -1,22 +1,61 @@
#pragma once
-#include "api/Transform.h"
+#include <cstdint>
+
+#include "api/Vector2.h"
namespace crepe {
+/**
+ * \brief Represents a particle in the particle emitter.
+ *
+ * This class stores information about a single particle, including its position,
+ * velocity, lifespan, and other properties. Particles can be updated over time
+ * to simulate movement and can also be reset or stopped.
+ */
class Particle {
public:
+ //! Position of the particle in 2D space.
Vector2 position;
+ //! Velocity vector indicating the speed and direction of the particle.
Vector2 velocity;
+ //! Accumulated force affecting the particle over time.
Vector2 force_over_time;
+ //! Total lifespan of the particle in milliseconds.
uint32_t lifespan;
+ //! Active state of the particle; true if it is in use, false otherwise.
bool active = false;
+ //! The time the particle has been alive, in milliseconds.
uint32_t time_in_life = 0;
+ //! The angle at which the particle is oriented or moving.
double angle;
Particle() = default;
- void reset(uint32_t lifespan, Vector2 position, Vector2 velocity,double angle);
+ /**
+ * \brief Resets the particle with new properties.
+ *
+ * This method initializes the particle with a specific lifespan, position,
+ * velocity, and angle, marking it as active and resetting its life counter.
+ *
+ * \param lifespan The lifespan of the particle in amount of updates.
+ * \param position The starting position of the particle.
+ * \param velocity The initial velocity of the particle.
+ * \param angle The angle of the particle's trajectory or orientation.
+ */
+ void reset(uint32_t lifespan, Vector2 position, Vector2 velocity, double angle);
+ /**
+ * \brief Updates the particle's state.
+ *
+ * Advances the particle's position based on its velocity and applies accumulated forces.
+ * Deactivates the particle if its lifespan has expired.
+ */
void update();
+ /**
+ * \brief Stops the particle's movement.
+ *
+ * Sets the particle's velocity to zero, effectively halting any further
+ * movement.
+ */
void stop_movement();
};
diff --git a/src/crepe/api/ParticleEmitter.cpp b/src/crepe/api/ParticleEmitter.cpp
index f585a81..000bf30 100644
--- a/src/crepe/api/ParticleEmitter.cpp
+++ b/src/crepe/api/ParticleEmitter.cpp
@@ -3,7 +3,7 @@
using namespace crepe;
-ParticleEmitter::ParticleEmitter(uint32_t game_object_id, const ParticleEmitterData& data) : Component(game_object_id),data(data) {
+ParticleEmitter::ParticleEmitter(uint32_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 f931e8c..2cda1bb 100644
--- a/src/crepe/api/ParticleEmitter.h
+++ b/src/crepe/api/ParticleEmitter.h
@@ -11,24 +11,44 @@ class Sprite;
namespace crepe {
+
+/**
+ * \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:
- struct ParticleBoundary{
+ /**
+ * \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 boundary_width = 0.0;
+ double width = 0.0;
//! boundary height (midpoint is emitter location)
- double boundary_height = 0.0;
+ double height = 0.0;
//! boundary offset from particle emitter location
- Vector2 boundary_offset;
+ Vector2 offset;
//! reset on exit or stop velocity and set max postion
bool reset_on_exit = false;
};
- struct ParticleEmitterData{
+ /**
+ * \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
- uint32_t max_particles = 0;
+ const uint32_t 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
@@ -46,17 +66,24 @@ public:
//! force over time (physics)
Vector2 force_over_time;
//! particle boundary
- ParticleBoundary boundary;
+ Boundary boundary;
//! collection of particles
std::vector<Particle> particles;
//! sprite reference
const Sprite* sprite;
};
public:
- ParticleEmitter(uint32_t game_object_id, const ParticleEmitterData& data);
+ /**
+ * \brief Constructs a ParticleEmitter data holder with specified settings.
+ *
+ * \param game_object_id Identifier for the game object using this emitter.
+ * \param data Configuration data defining particle properties.
+ */
+ ParticleEmitter(uint32_t game_object_id, const Data& data);
~ParticleEmitter();
public:
- ParticleEmitterData data;
+ //! Configuration data for particle emission settings.
+ Data data;
};
} // namespace crepe
diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp
index b2fe829..85321f0 100644
--- a/src/crepe/system/ParticleSystem.cpp
+++ b/src/crepe/system/ParticleSystem.cpp
@@ -116,9 +116,9 @@ int ParticleSystem::calculate_update(int count, double emission) {
void ParticleSystem::check_bounds(ParticleEmitter & emitter,const Transform& transform)
{
- Vector2 offset = emitter.data.boundary.boundary_offset + transform.position + emitter.data.position;
- double half_width = emitter.data.boundary.boundary_width / 2.0;
- double half_height = emitter.data.boundary.boundary_height / 2.0;
+ 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;
diff --git a/src/example/particles.cpp b/src/example/particles.cpp
index bcff48f..01e33cf 100644
--- a/src/example/particles.cpp
+++ b/src/example/particles.cpp
@@ -19,7 +19,6 @@ using namespace std;
int main(int argc, char * argv[]) {
- Color color(0, 0, 0, 0);
GameObject *game_object = new GameObject(0, "Name", "Tag", Vector2{0,0},0,0);
game_object->add_component<ParticleEmitter>(ParticleEmitter::ParticleEmitterData{
.position = {0,0},
diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt
index 0e4eaed..acab388 100644
--- a/src/test/CMakeLists.txt
+++ b/src/test/CMakeLists.txt
@@ -1,6 +1,7 @@
target_sources(test_main PUBLIC
dummy.cpp
# audio.cpp
- PhysicsTest.cpp
+ # PhysicsTest.cpp
+ ParticleTest.cpp
)
diff --git a/src/test/ParticleTest.cpp b/src/test/ParticleTest.cpp
new file mode 100644
index 0000000..aa63ccf
--- /dev/null
+++ b/src/test/ParticleTest.cpp
@@ -0,0 +1,86 @@
+#include <math.h>
+#include <crepe/ComponentManager.h>
+#include <crepe/api/Config.h>
+#include <crepe/api/GameObject.h>
+#include <crepe/api/Rigidbody.h>
+#include <crepe/api/Transform.h>
+#include <crepe/system/ParticleSystem.h>
+#include <gtest/gtest.h>
+
+
+using namespace std;
+using namespace std::chrono_literals;
+using namespace crepe;
+
+class ParticlesTest : public ::testing::Test {
+protected:
+ GameObject * game_object;
+ ParticleSystem particle_system;
+ void SetUp() override {
+ ComponentManager & mgr = ComponentManager::get_instance();
+ std::vector<std::reference_wrapper<Transform>> transforms
+ = mgr.get_components_by_id<Transform>(0);
+ if (transforms.empty()) {
+ game_object = new GameObject(0, "", "", Vector2{0, 0}, 0, 0);
+ game_object->add_component<ParticleEmitter>(ParticleEmitter::Data{
+ .position = {0,0},
+ .max_particles = 1,
+ .emission_rate = 0,
+ .min_speed = 0,
+ .max_speed = 0,
+ .min_angle = 0,
+ .max_angle = 0,
+ .begin_lifespan = 0,
+ .end_lifespan = 0,
+ .force_over_time = Vector2{0,0},
+ .boundary{
+ .width = 0,
+ .height = 0,
+ .offset = Vector2{0,0},
+ .reset_on_exit = false,
+ },
+ .sprite = nullptr,
+ });
+ }
+ transforms = mgr.get_components_by_id<Transform>(0);
+ Transform & transform = transforms.front().get();
+ transform.position.x = 0.0;
+ transform.position.y = 0.0;
+ transform.rotation = 0.0;
+ std::vector<std::reference_wrapper<Rigidbody>> rigidbodies
+ = mgr.get_components_by_id<Rigidbody>(0);
+ Rigidbody & rigidbody = rigidbodies.front().get();
+ rigidbody.data.angular_velocity = 0;
+ rigidbody.data.linear_velocity.x = 0;
+ rigidbody.data.linear_velocity.y = 0;
+ }
+};
+
+TEST_F(ParticlesTest, spawnParticle) {
+ Config::get_instance().physics.gravity = 1;
+ ComponentManager & mgr = ComponentManager::get_instance();
+ ParticleEmitter & emitter = mgr.get_components_by_id<ParticleEmitter>(0).front().get();
+ emitter.data.end_lifespan = 5;
+ emitter.data.boundary.height = 100;
+ emitter.data.boundary.width = 100;
+ emitter.data.max_speed = 1;
+ emitter.data.max_angle = 1;
+ particle_system.update();
+ //check if nothing happend
+ EXPECT_EQ(emitter.data.particles.size(), 0);
+ emitter.data.emission_rate = 1;
+ particle_system.update();
+ //check if particle spawned
+ EXPECT_EQ(emitter.data.particles.size(), 1);
+ for (auto& particle : emitter.data.particles) {
+ // Check velocity range
+ EXPECT_GE(particle.velocity.x, emitter.data.min_speed); // Speed should be greater than or equal to min_speed
+ EXPECT_LE(particle.velocity.x, emitter.data.max_speed); // Speed should be less than or equal to max_speed
+ EXPECT_GE(particle.velocity.y, emitter.data.min_speed); // Speed should be greater than or equal to min_speed
+ EXPECT_LE(particle.velocity.y, emitter.data.max_speed); // Speed should be less than or equal to max_speed
+
+ // Check angle range
+ EXPECT_GE(particle.angle, emitter.data.min_angle); // Angle should be greater than or equal to min_angle
+ EXPECT_LE(particle.angle, emitter.data.max_angle); // Angle should be less than or equal to max_angle
+ }
+}