diff options
| -rw-r--r-- | src/crepe/Particle.h | 43 | ||||
| -rw-r--r-- | src/crepe/api/ParticleEmitter.cpp | 2 | ||||
| -rw-r--r-- | src/crepe/api/ParticleEmitter.h | 45 | ||||
| -rw-r--r-- | src/crepe/system/ParticleSystem.cpp | 6 | ||||
| -rw-r--r-- | src/example/particles.cpp | 1 | ||||
| -rw-r--r-- | src/test/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/test/ParticleTest.cpp | 86 | 
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 +    } +} |