From eed6fab4b1c9cf4c301d6c0405218fd97b1ee917 Mon Sep 17 00:00:00 2001 From: Henrique Santiago Date: Sat, 17 Dec 2011 00:28:51 -0200 Subject: [PATCH] particles afectors upgrade and timer rework --- modules/particle.otpa | 20 ++++-- src/framework/graphics/particle.cpp | 31 ++++----- src/framework/graphics/particle.h | 9 ++- src/framework/graphics/particleaffector.cpp | 71 +++++++++++++++++++-- src/framework/graphics/particleaffector.h | 19 ++++-- src/framework/graphics/particleemitter.cpp | 27 ++++---- src/framework/graphics/particleemitter.h | 6 +- src/framework/graphics/particlesystem.cpp | 63 +++++++++++------- 8 files changed, 172 insertions(+), 74 deletions(-) diff --git a/modules/particle.otpa b/modules/particle.otpa index 88de09d7..e07c9744 100644 --- a/modules/particle.otpa +++ b/modules/particle.otpa @@ -1,16 +1,21 @@ ParticleSystem AttractionAffector + delay: 0 + duration: 12 destination: 200 200 acceleration: 64 velocity-reduction-percent: 0 Emitter position: 200 264 - duration: 12 - burstRate: 2 + duration: 2 + burstRate: 0.2 burstCount: 1 - delay: 0.5 - particle-duration: 9999 + delay: 0 + + particle-ignore-physics-after: 999 + + particle-duration: 12 particle-position-radius: 0 particle-velocity: 32 particle-velocity-angle: 0 @@ -21,9 +26,12 @@ ParticleSystem Emitter position: 200 200 - burstRate: 9999999999 + burstRate: 13 burstCount: 1 - particle-duration: 9999999 + duration: 12 + + particle-duration: 12 + particle-position-radius: 0 particle-velocity: 0 particle-velocity-angle: 0 diff --git a/src/framework/graphics/particle.cpp b/src/framework/graphics/particle.cpp index 5c9289f7..a083851d 100644 --- a/src/framework/graphics/particle.cpp +++ b/src/framework/graphics/particle.cpp @@ -24,7 +24,7 @@ #include "graphics.h" #include -Particle::Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, const Color& color, TexturePtr texture) +Particle::Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, float ignorePhysicsAfter, const Color& color, TexturePtr texture) { m_rect = Rect(pos, size); m_position = PointF(pos.x, pos.y); @@ -34,8 +34,8 @@ Particle::Particle(const Point& pos, const Size& size, const PointF& velocity, c m_color = color; m_texture = texture; m_duration = duration; - m_startTime = g_clock.time(); - m_lastUpdateTime = g_clock.time(); + m_ignorePhysicsAfter = ignorePhysicsAfter; + m_elapsedTime = 0; m_finished = false; } @@ -52,24 +52,25 @@ void Particle::render() } } -void Particle::update() +void Particle::update(double elapsedTime) { - float elapsedTime = g_clock.timeElapsed(m_lastUpdateTime); - m_lastUpdateTime = g_clock.time(); - // check if finished - if(m_duration > 0 && g_clock.timeElapsed(m_startTime) >= m_duration) { + if(m_duration > 0 && m_elapsedTime >= m_duration) { m_finished = true; return; } - // update position - PointF delta = m_velocity * elapsedTime; - delta.y *= -1; // painter orientate Y axis in the inverse direction - m_position += delta; + m_elapsedTime += elapsedTime; + + if(m_ignorePhysicsAfter < 0 || m_elapsedTime < m_ignorePhysicsAfter ) { + // update position + PointF delta = m_velocity * elapsedTime; + delta.y *= -1; // painter orientate Y axis in the inverse direction + m_position += delta; - // update acceleration - m_velocity += m_acceleration * elapsedTime; + // update acceleration + m_velocity += m_acceleration * elapsedTime; - m_rect.moveTo((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); + m_rect.moveTo((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); + } } diff --git a/src/framework/graphics/particle.h b/src/framework/graphics/particle.h index 71f49399..d51f0445 100644 --- a/src/framework/graphics/particle.h +++ b/src/framework/graphics/particle.h @@ -28,10 +28,10 @@ class Particle { public: - Particle(const Point& pos, const Size& size, const PointF& velocity, const PointF& acceleration, float duration, 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 Color& color = Fw::white, TexturePtr texture = nullptr); void render(); - void update(); + void update(double elapsedTime); bool hasFinished() { return m_finished; } @@ -49,9 +49,8 @@ private: PointF m_acceleration; Size m_size; Rect m_rect; - float m_duration; - double m_startTime; - double m_lastUpdateTime; + float m_duration, m_ignorePhysicsAfter; + double m_elapsedTime; bool m_finished; }; diff --git a/src/framework/graphics/particleaffector.cpp b/src/framework/graphics/particleaffector.cpp index d04f25da..04536e54 100644 --- a/src/framework/graphics/particleaffector.cpp +++ b/src/framework/graphics/particleaffector.cpp @@ -26,8 +26,64 @@ #define DEG_TO_RAD (acos(-1)/180.0) +ParticleAffector::ParticleAffector() +{ + m_active = false; + m_finished = false; + m_delay = 0; + m_duration = 0; + m_elapsedTime = 0; +} + +void ParticleAffector::update(double elapsedTime) +{ + if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) { + m_finished = true; + return; + } + + if(!m_active && m_elapsedTime > m_delay) + m_active = true; + + m_elapsedTime += elapsedTime; +} + +bool ParticleAffector::load(const OTMLNodePtr& node) +{ + float minDelay = 0, maxDelay = 0; + float minDuration = -1, maxDuration = -1; + + for(const OTMLNodePtr& childNode : node->children()) { + if(childNode->tag() == "delay") { + minDelay = childNode->value(); + maxDelay = childNode->value(); + } + else if(childNode->tag() == "min-delay") + minDelay = childNode->value(); + else if(childNode->tag() == "max-delay") + maxDelay = childNode->value(); + + if(childNode->tag() == "duration") { + minDuration = childNode->value(); + maxDuration = childNode->value(); + } + else if(childNode->tag() == "min-duration") + minDuration = childNode->value(); + else if(childNode->tag() == "max-duration") + maxDuration = childNode->value(); + } + + m_delay = Fw::randomRange(minDelay, maxDelay); + m_duration = Fw::randomRange(minDuration, maxDuration); + + return true; +} + bool GravityAffector::load(const OTMLNodePtr& node) { + if(!ParticleAffector::load(node)) + return false; + m_angle = 270 * DEG_TO_RAD; m_gravity = 9.8; @@ -40,8 +96,11 @@ bool GravityAffector::load(const OTMLNodePtr& node) return true; } -void GravityAffector::update(const ParticlePtr& particle, double elapsedTime) +void GravityAffector::updateParticle(const ParticlePtr& particle, double elapsedTime) { + if(!m_active) + return; + PointF velocity = particle->getVelocity(); velocity += PointF(m_gravity * elapsedTime * cos(m_angle), m_gravity * elapsedTime * sin(m_angle)); particle->setVelocity(velocity); @@ -49,6 +108,9 @@ void GravityAffector::update(const ParticlePtr& particle, double elapsedTime) bool AttractionAffector::load(const OTMLNodePtr& node) { + if(!ParticleAffector::load(node)) + return false; + m_acceleration = 32; for(const OTMLNodePtr& childNode : node->children()) { @@ -62,17 +124,16 @@ bool AttractionAffector::load(const OTMLNodePtr& node) return true; } -void AttractionAffector::update(const ParticlePtr& particle, double elapsedTime) +void AttractionAffector::updateParticle(const ParticlePtr& particle, double elapsedTime) { - // must change velocity angle, keeping modulus. + if(!m_active) + return; PointF pPosition = particle->getPosition(); - PointF d = PointF(m_destination.x - pPosition.x, pPosition.y - m_destination.y); if(d.length() == 0) return; PointF pVelocity = particle->getVelocity() + (d / d.length() * m_acceleration * elapsedTime); - particle->setVelocity(pVelocity - pVelocity * m_reduction/100.0 * elapsedTime); } diff --git a/src/framework/graphics/particleaffector.h b/src/framework/graphics/particleaffector.h index 6f0b5fbb..778f35d5 100644 --- a/src/framework/graphics/particleaffector.h +++ b/src/framework/graphics/particleaffector.h @@ -28,14 +28,25 @@ class ParticleAffector { public: - virtual bool load(const OTMLNodePtr&) { return true; } - virtual void update(const ParticlePtr&, double) {} + ParticleAffector(); + virtual ~ParticleAffector() { dump << "ParticleAffector deleted"; } + + void update(double elapsedTime); + virtual bool load(const OTMLNodePtr& node); + virtual void updateParticle(const ParticlePtr&, double) {} + + bool hasFinished() { return m_finished; } + +protected: + bool m_finished, m_active; + float m_delay, m_duration; + double m_elapsedTime; }; class GravityAffector : public ParticleAffector { public: bool load(const OTMLNodePtr& node); - void update(const ParticlePtr& particle, double elapsedTime); + void updateParticle(const ParticlePtr& particle, double elapsedTime); private: float m_angle, m_gravity; @@ -44,7 +55,7 @@ private: class AttractionAffector : public ParticleAffector { public: bool load(const OTMLNodePtr& node); - void update(const ParticlePtr& particle, double elapsedTime); + void updateParticle(const ParticlePtr& particle, double elapsedTime); private: Point m_destination; diff --git a/src/framework/graphics/particleemitter.cpp b/src/framework/graphics/particleemitter.cpp index 76f38e85..d71d6f48 100644 --- a/src/framework/graphics/particleemitter.cpp +++ b/src/framework/graphics/particleemitter.cpp @@ -38,7 +38,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent) m_delay = 0; m_burstRate = 1; m_burstCount = 32; m_currentBurst = 0; - m_startTime = g_clock.time(); + m_elapsedTime = 0; m_finished = false; // particles default configuration. (make them reasonable for user detect missing properties on scripts) @@ -50,6 +50,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent) m_pMaxSize = Size(32, 32); m_pMinDuration = 0; m_pMaxDuration = 10; + m_pIgnorePhysicsAfter = -1; m_pMinVelocity = 32; m_pMaxVelocity = 64; m_pMinVelocityAngle = 0; @@ -139,6 +140,8 @@ bool ParticleEmitter::load(const OTMLNodePtr& node) m_pMinDuration = childNode->value(); else if(childNode->tag() == "particle-max-duration") m_pMaxDuration = childNode->value(); + else if(childNode->tag() == "particle-ignore-physics-after") + m_pIgnorePhysicsAfter = childNode->value(); // visual else if(childNode->tag() == "particle-size") { @@ -157,24 +160,20 @@ bool ParticleEmitter::load(const OTMLNodePtr& node) return true; } -void ParticleEmitter::update() +void ParticleEmitter::update(double elapsedTime) { - float elapsedTime = g_clock.timeElapsed(m_startTime); - - // only start updating after delay - if(elapsedTime < m_delay) - return; - - // setup a new start time - elapsedTime -= m_delay; - // check if finished - if(m_duration > 0 && elapsedTime > m_duration) { + if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) { m_finished = true; return; } - int currentBurst = (elapsedTime / m_burstRate) + 1; + m_elapsedTime += elapsedTime; + + if(m_elapsedTime - elapsedTime < m_delay) + return; + + 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. @@ -199,7 +198,7 @@ void ParticleEmitter::update() PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle)); ParticleSystemPtr particleSystem = m_parent.lock(); - particleSystem->addParticle(ParticlePtr(new Particle(pPosition, pSize, pVelocity, pAcceleration, pDuration, m_pColor, m_pTexture))); + particleSystem->addParticle(ParticlePtr(new Particle(pPosition, pSize, pVelocity, pAcceleration, pDuration, m_pIgnorePhysicsAfter, m_pColor, m_pTexture))); } } diff --git a/src/framework/graphics/particleemitter.h b/src/framework/graphics/particleemitter.h index e1dbf9a1..a1c44caf 100644 --- a/src/framework/graphics/particleemitter.h +++ b/src/framework/graphics/particleemitter.h @@ -36,7 +36,7 @@ public: bool load(const OTMLNodePtr& node); - void update(); + void update(double elapsedTime); bool hasFinished() { return m_finished; } @@ -46,7 +46,7 @@ private: // self related Point m_position; float m_duration, m_delay; - double m_startTime; + double m_elapsedTime; bool m_finished; float m_burstRate; int m_currentBurst, m_burstCount; @@ -67,7 +67,7 @@ private: float m_pMinAccelerationAngle, m_pMaxAccelerationAngle; // particles duration - float m_pMinDuration, m_pMaxDuration; + float m_pMinDuration, m_pMaxDuration, m_pIgnorePhysicsAfter; // visual ralated Color m_pColor; diff --git a/src/framework/graphics/particlesystem.cpp b/src/framework/graphics/particlesystem.cpp index 4351b7bd..083efcb6 100644 --- a/src/framework/graphics/particlesystem.cpp +++ b/src/framework/graphics/particlesystem.cpp @@ -68,8 +68,7 @@ void ParticleSystem::render() void ParticleSystem::update() { - float elapsedTime = g_clock.timeElapsed(m_lastUpdateTime); - m_lastUpdateTime = g_clock.time(); + static const double delay = 0.0166; // 60 updates/s // check if finished if(m_particles.empty() && m_emitters.empty()) { @@ -77,30 +76,50 @@ void ParticleSystem::update() return; } - // update emitters - for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) { - const ParticleEmitterPtr& emitter = *it; - if(emitter->hasFinished()) { - it = m_emitters.erase(it); - continue; + // check time + double elapsedTime = g_clock.timeElapsed(m_lastUpdateTime); + if(elapsedTime < delay) + return; + m_lastUpdateTime = g_clock.time() - std::fmod(elapsedTime, delay); + + for(int i = 0; i < elapsedTime / delay; ++i) { + + // update emitters + for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) { + const ParticleEmitterPtr& emitter = *it; + if(emitter->hasFinished()) { + it = m_emitters.erase(it); + continue; + } + emitter->update(delay); + ++it; } - emitter->update(); - ++it; - } - // update particles - for(auto it = m_particles.begin(), end = m_particles.end(); it != end;) { - const ParticlePtr& particle = *it; - if(particle->hasFinished()) { - it = m_particles.erase(it); - continue; + // update affectors + for(auto it = m_affectors.begin(), end = m_affectors.end(); it != end;) { + const ParticleAffectorPtr& affector = *it; + if(affector->hasFinished()) { + it = m_affectors.erase(it); + continue; + } + affector->update(delay); + ++it; } - // pass particles through affectors - for(const ParticleAffectorPtr& particleAffector : m_affectors) - particleAffector->update(particle, elapsedTime); + // update particles + for(auto it = m_particles.begin(), end = m_particles.end(); it != end;) { + const ParticlePtr& particle = *it; + if(particle->hasFinished()) { + it = m_particles.erase(it); + continue; + } - particle->update(); - ++it; + // pass particles through affectors + for(const ParticleAffectorPtr& particleAffector : m_affectors) + particleAffector->updateParticle(particle, delay); + + particle->update(delay); + ++it; + } } }