particles afectors upgrade and timer rework

This commit is contained in:
Henrique Santiago 2011-12-17 00:28:51 -02:00
parent a4eed64709
commit eed6fab4b1
8 changed files with 173 additions and 75 deletions

View File

@ -1,16 +1,21 @@
ParticleSystem ParticleSystem
AttractionAffector AttractionAffector
delay: 0
duration: 12
destination: 200 200 destination: 200 200
acceleration: 64 acceleration: 64
velocity-reduction-percent: 0 velocity-reduction-percent: 0
Emitter Emitter
position: 200 264 position: 200 264
duration: 12 duration: 2
burstRate: 2 burstRate: 0.2
burstCount: 1 burstCount: 1
delay: 0.5 delay: 0
particle-duration: 9999
particle-ignore-physics-after: 999
particle-duration: 12
particle-position-radius: 0 particle-position-radius: 0
particle-velocity: 32 particle-velocity: 32
particle-velocity-angle: 0 particle-velocity-angle: 0
@ -21,9 +26,12 @@ ParticleSystem
Emitter Emitter
position: 200 200 position: 200 200
burstRate: 9999999999 burstRate: 13
burstCount: 1 burstCount: 1
particle-duration: 9999999 duration: 12
particle-duration: 12
particle-position-radius: 0 particle-position-radius: 0
particle-velocity: 0 particle-velocity: 0
particle-velocity-angle: 0 particle-velocity-angle: 0

View File

@ -24,7 +24,7 @@
#include "graphics.h" #include "graphics.h"
#include <framework/core/clock.h> #include <framework/core/clock.h>
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_rect = Rect(pos, size);
m_position = PointF(pos.x, pos.y); 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_color = color;
m_texture = texture; m_texture = texture;
m_duration = duration; m_duration = duration;
m_startTime = g_clock.time(); m_ignorePhysicsAfter = ignorePhysicsAfter;
m_lastUpdateTime = g_clock.time(); m_elapsedTime = 0;
m_finished = false; 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 // 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; m_finished = true;
return; return;
} }
// update position m_elapsedTime += elapsedTime;
PointF delta = m_velocity * elapsedTime;
delta.y *= -1; // painter orientate Y axis in the inverse direction
m_position += delta;
// update acceleration if(m_ignorePhysicsAfter < 0 || m_elapsedTime < m_ignorePhysicsAfter ) {
m_velocity += m_acceleration * elapsedTime; // update position
PointF delta = m_velocity * elapsedTime;
delta.y *= -1; // painter orientate Y axis in the inverse direction
m_position += delta;
m_rect.moveTo((int)m_position.x - m_size.width() / 2, (int)m_position.y - m_size.height() / 2); // 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);
}
} }

View File

@ -28,10 +28,10 @@
class Particle { class Particle {
public: 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 render();
void update(); void update(double elapsedTime);
bool hasFinished() { return m_finished; } bool hasFinished() { return m_finished; }
@ -49,9 +49,8 @@ private:
PointF m_acceleration; PointF m_acceleration;
Size m_size; Size m_size;
Rect m_rect; Rect m_rect;
float m_duration; float m_duration, m_ignorePhysicsAfter;
double m_startTime; double m_elapsedTime;
double m_lastUpdateTime;
bool m_finished; bool m_finished;
}; };

View File

@ -26,8 +26,64 @@
#define DEG_TO_RAD (acos(-1)/180.0) #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<float>();
maxDelay = childNode->value<float>();
}
else if(childNode->tag() == "min-delay")
minDelay = childNode->value<float>();
else if(childNode->tag() == "max-delay")
maxDelay = childNode->value<float>();
if(childNode->tag() == "duration") {
minDuration = childNode->value<float>();
maxDuration = childNode->value<float>();
}
else if(childNode->tag() == "min-duration")
minDuration = childNode->value<float>();
else if(childNode->tag() == "max-duration")
maxDuration = childNode->value<float>();
}
m_delay = Fw::randomRange(minDelay, maxDelay);
m_duration = Fw::randomRange(minDuration, maxDuration);
return true;
}
bool GravityAffector::load(const OTMLNodePtr& node) bool GravityAffector::load(const OTMLNodePtr& node)
{ {
if(!ParticleAffector::load(node))
return false;
m_angle = 270 * DEG_TO_RAD; m_angle = 270 * DEG_TO_RAD;
m_gravity = 9.8; m_gravity = 9.8;
@ -40,8 +96,11 @@ bool GravityAffector::load(const OTMLNodePtr& node)
return true; 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(); PointF velocity = particle->getVelocity();
velocity += PointF(m_gravity * elapsedTime * cos(m_angle), m_gravity * elapsedTime * sin(m_angle)); velocity += PointF(m_gravity * elapsedTime * cos(m_angle), m_gravity * elapsedTime * sin(m_angle));
particle->setVelocity(velocity); particle->setVelocity(velocity);
@ -49,6 +108,9 @@ void GravityAffector::update(const ParticlePtr& particle, double elapsedTime)
bool AttractionAffector::load(const OTMLNodePtr& node) bool AttractionAffector::load(const OTMLNodePtr& node)
{ {
if(!ParticleAffector::load(node))
return false;
m_acceleration = 32; m_acceleration = 32;
for(const OTMLNodePtr& childNode : node->children()) { for(const OTMLNodePtr& childNode : node->children()) {
@ -62,17 +124,16 @@ bool AttractionAffector::load(const OTMLNodePtr& node)
return true; 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 pPosition = particle->getPosition();
PointF d = PointF(m_destination.x - pPosition.x, pPosition.y - m_destination.y); PointF d = PointF(m_destination.x - pPosition.x, pPosition.y - m_destination.y);
if(d.length() == 0) if(d.length() == 0)
return; return;
PointF pVelocity = particle->getVelocity() + (d / d.length() * m_acceleration * elapsedTime); PointF pVelocity = particle->getVelocity() + (d / d.length() * m_acceleration * elapsedTime);
particle->setVelocity(pVelocity - pVelocity * m_reduction/100.0 * elapsedTime); particle->setVelocity(pVelocity - pVelocity * m_reduction/100.0 * elapsedTime);
} }

View File

@ -28,14 +28,25 @@
class ParticleAffector { class ParticleAffector {
public: public:
virtual bool load(const OTMLNodePtr&) { return true; } ParticleAffector();
virtual void update(const ParticlePtr&, double) {} 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 { class GravityAffector : public ParticleAffector {
public: public:
bool load(const OTMLNodePtr& node); bool load(const OTMLNodePtr& node);
void update(const ParticlePtr& particle, double elapsedTime); void updateParticle(const ParticlePtr& particle, double elapsedTime);
private: private:
float m_angle, m_gravity; float m_angle, m_gravity;
@ -44,7 +55,7 @@ private:
class AttractionAffector : public ParticleAffector { class AttractionAffector : public ParticleAffector {
public: public:
bool load(const OTMLNodePtr& node); bool load(const OTMLNodePtr& node);
void update(const ParticlePtr& particle, double elapsedTime); void updateParticle(const ParticlePtr& particle, double elapsedTime);
private: private:
Point m_destination; Point m_destination;

View File

@ -38,7 +38,7 @@ ParticleEmitter::ParticleEmitter(const ParticleSystemPtr& parent)
m_delay = 0; m_delay = 0;
m_burstRate = 1; m_burstCount = 32; m_burstRate = 1; m_burstCount = 32;
m_currentBurst = 0; m_currentBurst = 0;
m_startTime = g_clock.time(); m_elapsedTime = 0;
m_finished = false; m_finished = false;
// particles default configuration. (make them reasonable for user detect missing properties on scripts) // 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_pMaxSize = Size(32, 32);
m_pMinDuration = 0; m_pMinDuration = 0;
m_pMaxDuration = 10; m_pMaxDuration = 10;
m_pIgnorePhysicsAfter = -1;
m_pMinVelocity = 32; m_pMinVelocity = 32;
m_pMaxVelocity = 64; m_pMaxVelocity = 64;
m_pMinVelocityAngle = 0; m_pMinVelocityAngle = 0;
@ -139,6 +140,8 @@ bool ParticleEmitter::load(const OTMLNodePtr& node)
m_pMinDuration = childNode->value<float>(); m_pMinDuration = childNode->value<float>();
else if(childNode->tag() == "particle-max-duration") else if(childNode->tag() == "particle-max-duration")
m_pMaxDuration = childNode->value<float>(); m_pMaxDuration = childNode->value<float>();
else if(childNode->tag() == "particle-ignore-physics-after")
m_pIgnorePhysicsAfter = childNode->value<float>();
// visual // visual
else if(childNode->tag() == "particle-size") { else if(childNode->tag() == "particle-size") {
@ -157,24 +160,20 @@ bool ParticleEmitter::load(const OTMLNodePtr& node)
return true; 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 // check if finished
if(m_duration > 0 && elapsedTime > m_duration) { if(m_duration > 0 && m_elapsedTime >= m_duration + m_delay) {
m_finished = true; m_finished = true;
return; 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) { for(int b = m_currentBurst; b < currentBurst; ++b) {
// every burst created at same position. // every burst created at same position.
@ -199,7 +198,7 @@ void ParticleEmitter::update()
PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle)); PointF pAcceleration(pAccelerationAbs * cos(pAccelerationAngle), pAccelerationAbs * sin(pAccelerationAngle));
ParticleSystemPtr particleSystem = m_parent.lock(); 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)));
} }
} }

View File

@ -36,7 +36,7 @@ public:
bool load(const OTMLNodePtr& node); bool load(const OTMLNodePtr& node);
void update(); void update(double elapsedTime);
bool hasFinished() { return m_finished; } bool hasFinished() { return m_finished; }
@ -46,7 +46,7 @@ private:
// self related // self related
Point m_position; Point m_position;
float m_duration, m_delay; float m_duration, m_delay;
double m_startTime; double m_elapsedTime;
bool m_finished; bool m_finished;
float m_burstRate; float m_burstRate;
int m_currentBurst, m_burstCount; int m_currentBurst, m_burstCount;
@ -67,7 +67,7 @@ private:
float m_pMinAccelerationAngle, m_pMaxAccelerationAngle; float m_pMinAccelerationAngle, m_pMaxAccelerationAngle;
// particles duration // particles duration
float m_pMinDuration, m_pMaxDuration; float m_pMinDuration, m_pMaxDuration, m_pIgnorePhysicsAfter;
// visual ralated // visual ralated
Color m_pColor; Color m_pColor;

View File

@ -68,8 +68,7 @@ void ParticleSystem::render()
void ParticleSystem::update() void ParticleSystem::update()
{ {
float elapsedTime = g_clock.timeElapsed(m_lastUpdateTime); static const double delay = 0.0166; // 60 updates/s
m_lastUpdateTime = g_clock.time();
// check if finished // check if finished
if(m_particles.empty() && m_emitters.empty()) { if(m_particles.empty() && m_emitters.empty()) {
@ -77,30 +76,50 @@ void ParticleSystem::update()
return; return;
} }
// update emitters // check time
for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) { double elapsedTime = g_clock.timeElapsed(m_lastUpdateTime);
const ParticleEmitterPtr& emitter = *it; if(elapsedTime < delay)
if(emitter->hasFinished()) { return;
it = m_emitters.erase(it); m_lastUpdateTime = g_clock.time() - std::fmod(elapsedTime, delay);
continue;
}
emitter->update();
++it;
}
// update particles for(int i = 0; i < elapsedTime / delay; ++i) {
for(auto it = m_particles.begin(), end = m_particles.end(); it != end;) {
const ParticlePtr& particle = *it; // update emitters
if(particle->hasFinished()) { for(auto it = m_emitters.begin(), end = m_emitters.end(); it != end;) {
it = m_particles.erase(it); const ParticleEmitterPtr& emitter = *it;
continue; if(emitter->hasFinished()) {
it = m_emitters.erase(it);
continue;
}
emitter->update(delay);
++it;
} }
// pass particles through affectors // update affectors
for(const ParticleAffectorPtr& particleAffector : m_affectors) for(auto it = m_affectors.begin(), end = m_affectors.end(); it != end;) {
particleAffector->update(particle, elapsedTime); const ParticleAffectorPtr& affector = *it;
if(affector->hasFinished()) {
it = m_affectors.erase(it);
continue;
}
affector->update(delay);
++it;
}
particle->update(); // update particles
++it; 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;
}
// pass particles through affectors
for(const ParticleAffectorPtr& particleAffector : m_affectors)
particleAffector->updateParticle(particle, delay);
particle->update(delay);
++it;
}
} }
} }