diff --git a/examples/particles/src/main.cpp b/examples/particles/src/main.cpp index a5721ad..df4055d 100644 --- a/examples/particles/src/main.cpp +++ b/examples/particles/src/main.cpp @@ -29,27 +29,27 @@ namespace se = simpleengine; class ParticleEmitter : public se::particle::ParticleEmitter { private: - using super = se::particle::ParticleEmitter; + using Super = se::particle::ParticleEmitter; sf::Sprite sprite; sf::Texture texture; - super::ParticlePropertyVector properties = { + Super::ParticlePropertyVector properties = { std::make_shared(se::Range2f(-1.5f, 1.5f, -1.5f, 1.5f)), std::make_shared(se::Rangef(1'500, 9'500)) }; public: - ParticleEmitter() : super(texture, sf::Vector2f(350, 350), 0.4, 5, 1500, se::Range2f(-15, 15, -15, -15), se::particle::ParticleAttributes{0, sf::Vector2f(), 5, sf::Vector2f(2, 2)}, properties) { + ParticleEmitter() : Super(texture, sf::Vector2f(350, 350), 0.7, 5, 1500, se::Range2f(-50, 50, -50, 50), se::particle::ParticleAttributes{0, sf::Vector2f(), 5, sf::Vector2f(2, 2)}, properties) { texture.loadFromFile("particle.png"); // The particle I tested with was 5x5 pixels texture.setSmooth(true); } void Update(const float& delta_time) override { - super::Update(delta_time); + Super::Update(delta_time); } void Render(sf::RenderTarget* target) override { - super::Render(target); + Super::Render(target); } }; diff --git a/include/simpleengine/particle/emitter.h b/include/simpleengine/particle/emitter.h index 9356246..d6a3265 100644 --- a/include/simpleengine/particle/emitter.h +++ b/include/simpleengine/particle/emitter.h @@ -28,10 +28,6 @@ namespace simpleengine { sf::Vector2f start_velocity; float rotation_velocity = 0; sf::Vector2f scale = sf::Vector2f(1, 1); - - /* ParticleAttributes(uint32_t lifetime_ms, sf::Vector2f start_velocity, float rotation_velocity) : lifetime_ms(lifetime_ms), start_velocity(start_velocity), rotation_velocity(rotation_velocity) { - - } */ }; class ParticleEmitter : public simpleengine::Event { @@ -39,51 +35,12 @@ namespace simpleengine { using ParticlePropertyPtr = std::shared_ptr; using ParticlePropertyVector = std::vector; public: - explicit ParticleEmitter(sf::Texture& texture, sf::Vector2f position, double emit_variance, uint32_t emit_count, uint32_t particle_count, Range2f particle_range, ParticleAttributes attributes, ParticlePropertyVector& properties) - : texture(texture), position(position), emit_variance(emit_variance), emit_count(emit_count), particle_count(particle_count), particle_range(particle_range), attributes(attributes), properties(properties) { - time.restart(); - } + ParticleEmitter(sf::Texture& texture, sf::Vector2f position, double emit_variance, uint32_t emit_count, uint32_t particle_count, Range2f particle_range, ParticleAttributes attributes, ParticlePropertyVector& properties); - void SetProperties(ParticlePropertyVector& properties) { - this->properties = properties; - } + void SetProperties(ParticlePropertyVector& properties); - virtual void Update(const float& delta_time) override { - for (std::vector::iterator it = particles.begin(); it != particles.end(); ) { - it->Update(delta_time); - - if (it->IsDestroying()) { - it = particles.erase(it); - } else { - it++; - } - } - - if (particles.size() < particle_count) { - if (random.NextInRange(0, 1) < emit_variance) { - for (uint32_t i = 0; i < emit_count; i++) { - Particle particle(texture, attributes.start_velocity, attributes.lifetime_ms, attributes.rotation_velocity, properties); - - // Offset the position of the particle randomly - sf::Vector2f new_pos; - new_pos.x = random.NextInRange(particle_range.min_x, particle_range.max_x); - new_pos.y = random.NextInRange(particle_range.min_y, particle_range.max_y); - new_pos += position; - particle.GetSprite().setPosition(new_pos); - - particle.GetSprite().setScale(attributes.scale.x, attributes.scale.y); - - particles.emplace_back(std::move(particle)); - } - } - } - } - - virtual void Render(sf::RenderTarget* target) override { - for (simpleengine::particle::Particle particle : particles) { - particle.Render(target); - } - } + virtual void Update(const float& delta_time) override; + virtual void Render(sf::RenderTarget* target) override; protected: sf::Texture& texture; sf::Vector2f position; diff --git a/include/simpleengine/particle/particle.h b/include/simpleengine/particle/particle.h index 37af348..112abc9 100644 --- a/include/simpleengine/particle/particle.h +++ b/include/simpleengine/particle/particle.h @@ -21,63 +21,18 @@ namespace simpleengine { namespace particle { class Particle : public simpleengine::Event { private: - using super = simpleengine::Event; + using Super = simpleengine::Event; protected: using ParticlePropertyPtr = std::shared_ptr; using ParticlePropertyVector = std::vector; public: - Particle(sf::Texture& texture, sf::Vector2f velocity, uint32_t lifetime_ms, float rotation_velocity, - ParticlePropertyVector properties) : simpleengine::Event(nullptr), velocity(velocity), lifetime_ms(lifetime_ms), - rotation_velocity(rotation_velocity), properties(properties) { - age_clock.restart(); - sprite.setTexture(texture); + Particle(sf::Texture& texture, sf::Vector2f velocity, uint32_t lifetime_ms, float rotation_velocity, ParticlePropertyVector properties); - for (ParticlePropertyPtr property : properties) { - property->OnParticleSpawn(*this); - } - } + virtual void Update(const float& delta_time) override; + virtual void Render(sf::RenderTarget* target) override; - virtual void Update(const float& delta_time) override { - if (age_clock.getElapsedTime().asMilliseconds() >= lifetime_ms) { - super::Destroy(); - return; - } - - for (ParticlePropertyPtr property : properties) { - property->Update(*this); - } - - sprite.move(velocity.x, velocity.y); - } - - virtual void Render(sf::RenderTarget* target) override { - target->draw(sprite); - } - - sf::Sprite& GetSprite() { - return sprite; - } - - /* void SetVelocity(const sf::Vector2f& velocity) { - this->velocity = velocity; - } - - const sf::Vector2f& GetVelocity() { - return velocity; - } - - void SetRotationVelocity(const float& rotation_velocity) { - this->rotation_velocity = rotation_velocity; - } - - const float& GetRotationVelocity() { - return rotation_velocity; - } - private: */ - - const sf::Time GetAge() const { - return age_clock.getElapsedTime(); - } + sf::Sprite& GetSprite(); + const sf::Time GetAge() const; sf::Sprite sprite; sf::Vector2f velocity; diff --git a/include/simpleengine/particle/properties/random_lifetime_property.h b/include/simpleengine/particle/properties/random_lifetime_property.h index 5567579..b30fa15 100644 --- a/include/simpleengine/particle/properties/random_lifetime_property.h +++ b/include/simpleengine/particle/properties/random_lifetime_property.h @@ -20,6 +20,10 @@ namespace simpleengine { } + RandomLifetimeParticleProperty(float min, float max) : RandomLifetimeParticleProperty(Rangef(min, max)) { + + } + void OnParticleSpawn(simpleengine::particle::Particle& particle) override { simpleengine::Random rand; particle.lifetime_ms = rand.NextInRange(range.min, range.max); diff --git a/include/simpleengine/particle/properties/random_velocity_property.h b/include/simpleengine/particle/properties/random_velocity_property.h index d4f8972..c079580 100644 --- a/include/simpleengine/particle/properties/random_velocity_property.h +++ b/include/simpleengine/particle/properties/random_velocity_property.h @@ -20,6 +20,11 @@ namespace simpleengine { } + RandomVelocityParticleProperty(float min_x, float max_x, float min_y, float max_y) + : RandomVelocityParticleProperty(Range2f(min_x, max_x, min_y, max_y)) { + + } + void OnParticleSpawn(simpleengine::particle::Particle& particle) override { simpleengine::Random rand; sf::Vector2f velocity; diff --git a/src/particle/emitter.cpp b/src/particle/emitter.cpp new file mode 100644 index 0000000..3f3f545 --- /dev/null +++ b/src/particle/emitter.cpp @@ -0,0 +1,48 @@ +#include "particle/emitter.h" + +simpleengine::particle::ParticleEmitter::ParticleEmitter(sf::Texture& texture, sf::Vector2f position, double emit_variance, uint32_t emit_count, uint32_t particle_count, Range2f particle_range, ParticleAttributes attributes, ParticlePropertyVector& properties) : texture(texture), position(position), emit_variance(emit_variance), emit_count(emit_count), particle_count(particle_count), particle_range(particle_range), attributes(attributes), properties(properties) { + time.restart(); +} + +void simpleengine::particle::ParticleEmitter::SetProperties(ParticlePropertyVector& properties) { + this->properties = properties; +} + +void simpleengine::particle::ParticleEmitter::Update(const float &delta_time) { + // Update particles and check if they are being destroyed. If they are, destroy them. + for (std::vector::iterator it = particles.begin(); it != particles.end(); ) { + it->Update(delta_time); + + if (it->IsDestroying()) { + it = particles.erase(it); + } else { + it++; + } + } + + // Check if we can spawn particles with max particle count, also use chance to check if we can. + if (particles.size() < particle_count && random.NextInRange(0, 1) < emit_variance) { + // Make sure that we don't emit too many particles to go over the max particle count + uint32_t emitting_ct = (particles.size() + emit_count > particle_count) ? particle_count - particles.size() : emit_count; + for (uint32_t i = 0; i < emitting_ct; i++) { + Particle particle(texture, attributes.start_velocity, attributes.lifetime_ms, attributes.rotation_velocity, properties); + + // Offset the position of the particle randomly + sf::Vector2f new_pos; + new_pos.x = random.NextInRange(particle_range.min_x, particle_range.max_x); + new_pos.y = random.NextInRange(particle_range.min_y, particle_range.max_y); + new_pos += position; + particle.GetSprite().setPosition(new_pos); + + particle.GetSprite().setScale(attributes.scale.x, attributes.scale.y); + + particles.emplace_back(std::move(particle)); + } + } +} + +void simpleengine::particle::ParticleEmitter::Render(sf::RenderTarget *target) { + for (simpleengine::particle::Particle particle : particles) { + particle.Render(target); + } +} \ No newline at end of file diff --git a/src/particle/particle.cpp b/src/particle/particle.cpp new file mode 100644 index 0000000..23383a0 --- /dev/null +++ b/src/particle/particle.cpp @@ -0,0 +1,40 @@ +#include "particle/particle.h" + +simpleengine::particle::Particle::Particle(sf::Texture& texture, sf::Vector2f velocity, uint32_t lifetime_ms, float rotation_velocity, + ParticlePropertyVector properties) : Super(nullptr), velocity(velocity), lifetime_ms(lifetime_ms), + rotation_velocity(rotation_velocity), properties(properties) { + age_clock.restart(); // Start age clock + sprite.setTexture(texture); + + // Trigger OnParticleSpawn for particle properities. + for (ParticlePropertyPtr property : properties) { + property->OnParticleSpawn(*this); + } +} + +void simpleengine::particle::Particle::Update(const float& delta_time) { + // If the particle is older than its lifetime, destroy it. + if (age_clock.getElapsedTime().asMilliseconds() >= lifetime_ms) { + Super::Destroy(); + return; + } + + // Update all properties. + for (ParticlePropertyPtr property : properties) { + property->Update(*this); + } + + sprite.move(velocity.x, velocity.y); +} + +void simpleengine::particle::Particle::Render(sf::RenderTarget* target) { + target->draw(sprite); +} + +sf::Sprite& simpleengine::particle::Particle::GetSprite() { + return sprite; +} + +const sf::Time simpleengine::particle::Particle::GetAge() const { + return age_clock.getElapsedTime(); +} \ No newline at end of file