particles afectors upgrade and timer rework
This commit is contained in:
parent
a4eed64709
commit
eed6fab4b1
|
@ -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
|
||||
|
|
|
@ -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,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;
|
||||
|
||||
// update acceleration
|
||||
m_velocity += m_acceleration * 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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
emitter->update();
|
||||
++it;
|
||||
}
|
||||
// check time
|
||||
double elapsedTime = g_clock.timeElapsed(m_lastUpdateTime);
|
||||
if(elapsedTime < delay)
|
||||
return;
|
||||
m_lastUpdateTime = g_clock.time() - std::fmod(elapsedTime, delay);
|
||||
|
||||
// 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;
|
||||
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;
|
||||
}
|
||||
|
||||
// pass particles through affectors
|
||||
for(const ParticleAffectorPtr& particleAffector : m_affectors)
|
||||
particleAffector->update(particle, elapsedTime);
|
||||
// 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;
|
||||
}
|
||||
|
||||
particle->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;
|
||||
}
|
||||
|
||||
// pass particles through affectors
|
||||
for(const ParticleAffectorPtr& particleAffector : m_affectors)
|
||||
particleAffector->updateParticle(particle, delay);
|
||||
|
||||
particle->update(delay);
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue