diff options
Diffstat (limited to 'src/crepe/system')
| -rw-r--r-- | src/crepe/system/ParticleSystem.cpp | 159 | ||||
| -rw-r--r-- | src/crepe/system/ParticleSystem.h | 10 | 
2 files changed, 131 insertions, 38 deletions
| diff --git a/src/crepe/system/ParticleSystem.cpp b/src/crepe/system/ParticleSystem.cpp index 397b586..23534a3 100644 --- a/src/crepe/system/ParticleSystem.cpp +++ b/src/crepe/system/ParticleSystem.cpp @@ -1,62 +1,149 @@  #include <cmath>  #include <ctime> +#include <cstdlib> -#include "../ComponentManager.h" -#include "../api/ParticleEmitter.h" +#include "api/ParticleEmitter.h" +#include "api/Vector2.h" +#include "ComponentManager.h"  #include "ParticleSystem.h"  using namespace crepe; -ParticleSystem::ParticleSystem() : elapsed_time(0.0f) {} +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>(); -	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(); + +		//	Check if within boundary +		check_bounds(emitter,transform); +		 +		// 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 (size_t j = 0; j < emitter.data.particles.size(); j++) { +			if (emitter.data.particles[j].active) { +				emitter.data.particles[j].update();  			}  		}  	} +	update_count++; +	if(update_count == MAX_UPDATE_COUNT) update_count = 0;  } -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); +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) { +			// 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 { -		random_angle = emitter.min_angle -					   + (std::rand() -						  % (static_cast<uint32_t>(emitter.max_angle -												   - emitter.min_angle + 1))); +			// 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; +			}  	} -	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); + +	// Generate a random speed between min_speed and max_speed +	double speed_offset = emitter.data.max_speed - emitter.data.min_speed; +	double random_speed = emitter.data.min_speed + static_cast<double>(std::rand() % static_cast<uint32_t>(speed_offset)); + +	// Convert random_angle to radians +	double angle_radians = random_angle * DEG_TO_RAD; + +	Vector2 velocity = { +        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);  			break;  		}  	}  } + +int ParticleSystem::calculate_update(int count, double emission) { + +		//get interger part of the emission +		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; +			} +    } +		 +    // For integer emissions, return the emission directly +    return static_cast<int>(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; + +		// 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; + +		std::vector<Particle>& particles = emitter.data.particles; +		for (Particle& particle : particles) +		{ +				const Vector2& position = particle.position; + +				// 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) +						{ +								particle.active = false; +						} +						else +						{ +								particle.velocity = {0, 0}; +								//todo add that particle goes back to boundary +						} +				} +		} +} diff --git a/src/crepe/system/ParticleSystem.h b/src/crepe/system/ParticleSystem.h index 3ac1d3f..3b9cb54 100644 --- a/src/crepe/system/ParticleSystem.h +++ b/src/crepe/system/ParticleSystem.h @@ -10,9 +10,15 @@ public:  	void update();  private: -	void emit_particle(ParticleEmitter & emitter); //emits a new particle +	void emit_particle(ParticleEmitter & emitter,const Transform& transform); +	int calculate_update(int count, double emission); +	void check_bounds(ParticleEmitter & emitter,const Transform& transform); -	float elapsed_time; //elapsed time since the last emission +private: +	//! 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;  };  } // namespace crepe |