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
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

View File

@ -24,7 +24,7 @@
#include "graphics.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_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,17 +52,17 @@ 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;
}
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
@ -73,3 +73,4 @@ void Particle::update()
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 {
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;
};

View File

@ -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<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)
{
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);
}

View File

@ -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;

View File

@ -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<float>();
else if(childNode->tag() == "particle-max-duration")
m_pMaxDuration = childNode->value<float>();
else if(childNode->tag() == "particle-ignore-physics-after")
m_pIgnorePhysicsAfter = childNode->value<float>();
// 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)));
}
}

View File

@ -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;

View File

@ -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,6 +76,14 @@ void ParticleSystem::update()
return;
}
// 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;
@ -84,7 +91,18 @@ void ParticleSystem::update()
it = m_emitters.erase(it);
continue;
}
emitter->update();
emitter->update(delay);
++it;
}
// 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;
}
@ -98,9 +116,10 @@ void ParticleSystem::update()
// pass particles through affectors
for(const ParticleAffectorPtr& particleAffector : m_affectors)
particleAffector->update(particle, elapsedTime);
particleAffector->updateParticle(particle, delay);
particle->update();
particle->update(delay);
++it;
}
}
}