diff --git a/modules/particle.otpa b/modules/particle.otpa index e07c9744..fad1912b 100644 --- a/modules/particle.otpa +++ b/modules/particle.otpa @@ -1,15 +1,15 @@ ParticleSystem AttractionAffector delay: 0 - duration: 12 - destination: 200 200 + duration: 999 + position: 200 200 acceleration: 64 velocity-reduction-percent: 0 Emitter position: 200 264 duration: 2 - burstRate: 0.2 + burstRate: 3 burstCount: 1 delay: 0 @@ -21,22 +21,6 @@ ParticleSystem particle-velocity-angle: 0 particle-acceleration: 0 particle-size: 32 32 - particle-color: #33ff33ff - particle-texture: circle2.png - - Emitter - position: 200 200 - burstRate: 13 - burstCount: 1 - duration: 12 - - particle-duration: 12 - - particle-position-radius: 0 - particle-velocity: 0 - particle-velocity-angle: 0 - particle-acceleration: 0 - particle-size: 32 32 - particle-color: #33ff33ff + particle-colors: #00ff00ff #ff0000ff #0000ffff #00ff00ff #00ff0000 + particle-colors-stops: 3 6 9 12 particle-texture: circle2.png - diff --git a/src/framework/graphics/particle.cpp b/src/framework/graphics/particle.cpp index a083851d..7cebf131 100644 --- a/src/framework/graphics/particle.cpp +++ b/src/framework/graphics/particle.cpp @@ -24,14 +24,17 @@ #include "graphics.h" #include -Particle::Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, float ignorePhysicsAfter, const Color& color, TexturePtr texture) +Particle::Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, float ignorePhysicsAfter, const std::vector& colors, const std::vector& colorsStops, TexturePtr texture) { + m_colors = colors; + m_colorsStops = colorsStops; + m_rect = Rect(pos, size); m_position = PointF(pos.x, pos.y); m_size = size; m_velocity = velocity; m_acceleration = acceleration; - m_color = color; + m_texture = texture; m_duration = duration; m_ignorePhysicsAfter = ignorePhysicsAfter; @@ -55,13 +58,14 @@ void Particle::render() void Particle::update(double elapsedTime) { // check if finished - if(m_duration > 0 && m_elapsedTime >= m_duration) { + if(m_duration >= 0 && m_elapsedTime >= m_duration) { m_finished = true; return; } - m_elapsedTime += elapsedTime; + updateColor(); + // update position if(m_ignorePhysicsAfter < 0 || m_elapsedTime < m_ignorePhysicsAfter ) { // update position PointF delta = m_velocity * elapsedTime; @@ -73,4 +77,25 @@ void Particle::update(double elapsedTime) m_rect.moveTo((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); } + + m_elapsedTime += elapsedTime; +} + +void Particle::updateColor() +{ + if(m_elapsedTime < m_colorsStops[1]) { + m_color.setRGBA(m_colors[0].r() + (m_colors[1].r() - m_colors[0].r()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]), + m_colors[0].g() + (m_colors[1].g() - m_colors[0].g()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]), + m_colors[0].b() + (m_colors[1].b() - m_colors[0].b()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0]), + m_colors[0].a() + (m_colors[1].a() - m_colors[0].a()) / (m_colorsStops[1] - m_colorsStops[0]) * (m_elapsedTime - m_colorsStops[0])); + } + else { + if(m_colors.size() > 1) { + m_colors.erase(m_colors.begin()); + m_colorsStops.erase(m_colorsStops.begin()); + } + else { + m_color = m_colors[0]; + } + } } diff --git a/src/framework/graphics/particle.h b/src/framework/graphics/particle.h index d51f0445..dde8b210 100644 --- a/src/framework/graphics/particle.h +++ b/src/framework/graphics/particle.h @@ -28,7 +28,7 @@ class Particle { public: - Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, float ignorePhysicsAfter, const Color& color = Fw::white, TexturePtr texture = nullptr); + Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, float ignorePhysicsAfter, const std::vector& colors, const std::vector& colorsStops, TexturePtr texture = nullptr); void render(); void update(double elapsedTime); @@ -42,7 +42,11 @@ public: void setVelocity(const PointF& velocity) { m_velocity = velocity; } private: + void updateColor(); + Color m_color; + std::vector m_colors; + std::vector m_colorsStops; TexturePtr m_texture; PointF m_position; PointF m_velocity; diff --git a/src/framework/graphics/particleaffector.cpp b/src/framework/graphics/particleaffector.cpp index 04536e54..b9f0851b 100644 --- a/src/framework/graphics/particleaffector.cpp +++ b/src/framework/graphics/particleaffector.cpp @@ -37,7 +37,7 @@ ParticleAffector::ParticleAffector() void ParticleAffector::update(double elapsedTime) { - if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) { + if(m_duration >= 0 && m_elapsedTime >= m_duration + m_delay) { m_finished = true; return; } @@ -114,8 +114,8 @@ bool AttractionAffector::load(const OTMLNodePtr& node) m_acceleration = 32; for(const OTMLNodePtr& childNode : node->children()) { - if(childNode->tag() == "destination") - m_destination = childNode->value(); + if(childNode->tag() == "position") + m_position = childNode->value(); else if(childNode->tag() == "acceleration") m_acceleration = childNode->value(); else if(childNode->tag() == "velocity-reduction-percent") @@ -130,7 +130,7 @@ void AttractionAffector::updateParticle(const ParticlePtr& particle, double elap return; PointF pPosition = particle->getPosition(); - PointF d = PointF(m_destination.x - pPosition.x, pPosition.y - m_destination.y); + PointF d = PointF(m_position.x - pPosition.x, pPosition.y - m_position.y); if(d.length() == 0) return; diff --git a/src/framework/graphics/particleaffector.h b/src/framework/graphics/particleaffector.h index 778f35d5..e987788d 100644 --- a/src/framework/graphics/particleaffector.h +++ b/src/framework/graphics/particleaffector.h @@ -58,7 +58,7 @@ public: void updateParticle(const ParticlePtr& particle, double elapsedTime); private: - Point m_destination; + Point m_position; float m_acceleration, m_reduction; }; diff --git a/src/framework/graphics/particleemitter.cpp b/src/framework/graphics/particleemitter.cpp index d71d6f48..3b950e40 100644 --- a/src/framework/graphics/particleemitter.cpp +++ b/src/framework/graphics/particleemitter.cpp @@ -40,6 +40,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent) m_currentBurst = 0; m_elapsedTime = 0; m_finished = false; + m_active = false; // particles default configuration. (make them reasonable for user detect missing properties on scripts) m_pMinPositionRadius = 0; @@ -59,7 +60,6 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent) m_pMaxAcceleration = 64; m_pMinAccelerationAngle = 0; m_pMaxAccelerationAngle = 360; - m_pColor = Color(255, 255, 255, 128); } bool ParticleEmitter::load(const OTMLNodePtr& node) @@ -152,55 +152,70 @@ bool ParticleEmitter::load(const OTMLNodePtr& node) m_pMinSize = childNode->value(); else if(childNode->tag() == "particle-max-size") m_pMaxSize = childNode->value(); - else if(childNode->tag() == "particle-color") - m_pColor = childNode->value(); + + else if(childNode->tag() == "particle-colors") + m_pColors = Fw::split(childNode->value()); + else if(childNode->tag() == "particle-colors-stops") + m_pColorsStops = Fw::split(childNode->value()); else if(childNode->tag() == "particle-texture") m_pTexture = g_textures.getTexture(childNode->value()); } + + if(m_pColors.empty()) + m_pColors.push_back(Color(255, 255, 255, 128)); + m_pColorsStops.insert(m_pColorsStops.begin(), 0); + + if(m_pColors.size() != m_pColorsStops.size()) { + logError("particle colors must be equal to colorstops-1"); + return false; + } + return true; } void ParticleEmitter::update(double elapsedTime) { // check if finished - if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) { + if(m_duration >= 0 && m_elapsedTime >= m_duration + m_delay) { m_finished = true; return; } - m_elapsedTime += elapsedTime; - - if(m_elapsedTime - elapsedTime < m_delay) - return; + if(!m_active && m_elapsedTime > m_delay) + m_active = true; - int currentBurst = std::floor((m_elapsedTime - m_delay) / m_burstRate) + 1; - for(int b = m_currentBurst; b < currentBurst; ++b) { + if(m_active) { + int currentBurst = std::floor((m_elapsedTime - m_delay) / m_burstRate) + 1; + for(int b = m_currentBurst; b < currentBurst; ++b) { - // every burst created at same position. - float pRadius = Fw::randomRange(m_pMinPositionRadius, m_pMaxPositionRadius); - float pAngle = Fw::randomRange(m_pMinPositionAngle, m_pMaxPositionAngle); + // every burst created at same position. + float pRadius = Fw::randomRange(m_pMinPositionRadius, m_pMaxPositionRadius); + float pAngle = Fw::randomRange(m_pMinPositionAngle, m_pMaxPositionAngle); - Point pPosition = m_position + Point(pRadius * cos(pAngle), pRadius * sin(pAngle)); + Point pPosition = m_position + Point(pRadius * cos(pAngle), pRadius * sin(pAngle)); - for(int p = 0; p < m_burstCount; ++p) { + for(int p = 0; p < m_burstCount; ++p) { - Size pSize = Size(Fw::randomRange(m_pMinSize.width(), m_pMaxSize.width()), Fw::randomRange(m_pMinSize.height(), m_pMaxSize.height())); - float pDuration = Fw::randomRange(m_pMinDuration, m_pMaxDuration); + Size pSize = Size(Fw::randomRange(m_pMinSize.width(), m_pMaxSize.width()), Fw::randomRange(m_pMinSize.height(), m_pMaxSize.height())); + float pDuration = Fw::randomRange(m_pMinDuration, m_pMaxDuration); - // particles initial velocity - float pVelocityAbs = Fw::randomRange(m_pMinVelocity, m_pMaxVelocity); - float pVelocityAngle = Fw::randomRange(m_pMinVelocityAngle, m_pMaxVelocityAngle); - PointF pVelocity(pVelocityAbs * cos(pVelocityAngle), pVelocityAbs * sin(pVelocityAngle)); + // particles initial velocity + float pVelocityAbs = Fw::randomRange(m_pMinVelocity, m_pMaxVelocity); + float pVelocityAngle = Fw::randomRange(m_pMinVelocityAngle, m_pMaxVelocityAngle); + PointF pVelocity(pVelocityAbs * cos(pVelocityAngle), pVelocityAbs * sin(pVelocityAngle)); - // particles initial acceleration - float pAccelerationAbs = Fw::randomRange(m_pMinAcceleration, m_pMaxAcceleration); - float pAccelerationAngle = Fw::randomRange(m_pMinAccelerationAngle, m_pMaxAccelerationAngle); - PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle)); + // particles initial acceleration + float pAccelerationAbs = Fw::randomRange(m_pMinAcceleration, m_pMaxAcceleration); + float pAccelerationAngle = Fw::randomRange(m_pMinAccelerationAngle, m_pMaxAccelerationAngle); + PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle)); - ParticleSystemPtr particleSystem = m_parent.lock(); - particleSystem->addParticle(ParticlePtr(new Particle(pPosition, pSize, pVelocity, pAcceleration, pDuration, m_pIgnorePhysicsAfter, m_pColor, m_pTexture))); + ParticleSystemPtr particleSystem = m_parent.lock(); + particleSystem->addParticle(ParticlePtr(new Particle(pPosition, pSize, pVelocity, pAcceleration, pDuration, m_pIgnorePhysicsAfter, m_pColors, m_pColorsStops, m_pTexture))); + } } + + m_currentBurst = currentBurst; } - m_currentBurst = currentBurst; + m_elapsedTime += elapsedTime; } diff --git a/src/framework/graphics/particleemitter.h b/src/framework/graphics/particleemitter.h index a1c44caf..2c071eb3 100644 --- a/src/framework/graphics/particleemitter.h +++ b/src/framework/graphics/particleemitter.h @@ -47,7 +47,7 @@ private: Point m_position; float m_duration, m_delay; double m_elapsedTime; - bool m_finished; + bool m_finished, m_active; float m_burstRate; int m_currentBurst, m_burstCount; @@ -70,7 +70,8 @@ private: float m_pMinDuration, m_pMaxDuration, m_pIgnorePhysicsAfter; // visual ralated - Color m_pColor; + std::vector m_pColors; + std::vector m_pColorsStops; TexturePtr m_pTexture; }; diff --git a/src/framework/graphics/particlesystem.cpp b/src/framework/graphics/particlesystem.cpp index 083efcb6..b6b91f5e 100644 --- a/src/framework/graphics/particlesystem.cpp +++ b/src/framework/graphics/particlesystem.cpp @@ -35,7 +35,8 @@ bool ParticleSystem::load(const OTMLNodePtr& node) for(const OTMLNodePtr& childNode : node->children()) { if(childNode->tag() == "Emitter") { ParticleEmitterPtr emitter = ParticleEmitterPtr(new ParticleEmitter(shared_from_this())); - emitter->load(childNode); + if(!emitter->load(childNode)) + return false; m_emitters.push_back(emitter); } else if(childNode->tag().find("Affector") != std::string::npos) { @@ -47,7 +48,8 @@ bool ParticleSystem::load(const OTMLNodePtr& node) affector = ParticleAffectorPtr(new AttractionAffector); if(affector) { - affector->load(childNode); + if(!affector->load(childNode)) + return false; m_affectors.push_back(affector); } }