From ab858bc8e650f1120495f968379f37257c774b5f Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Tue, 17 May 2011 13:48:20 +1000 Subject: [PATCH] Fix emitter burst method bugs Burst will now always burst at the x,y where it was called, and doesn't leave trails between close bursts. Kill affector also gets a fix for double killing things sometimes. --- src/imports/particles/followemitter.cpp | 123 ++++++++++++++-------------- src/imports/particles/killaffector.cpp | 6 +- src/imports/particles/particleemitter.cpp | 3 +- src/imports/particles/particleemitter.h | 7 +- src/imports/particles/trailsemitter.cpp | 130 ++++++++++++++++-------------- 5 files changed, 139 insertions(+), 130 deletions(-) diff --git a/src/imports/particles/followemitter.cpp b/src/imports/particles/followemitter.cpp index 9e1ec7b..17a544f 100644 --- a/src/imports/particles/followemitter.cpp +++ b/src/imports/particles/followemitter.cpp @@ -84,7 +84,7 @@ void FollowEmitter::emitWindow(int timeStamp) { if (m_system == 0) return; - if(!m_emitting && !m_burstLeft && !m_emitLeft) + if(!m_emitting && !m_burstLeft && m_burstQueue.isEmpty()) return; if(m_followCount != m_system->m_groupData[m_system->m_groupIds[m_follow]]->size){ qreal oldPPS = m_particlesPerSecond; @@ -123,70 +123,69 @@ void FollowEmitter::emitWindow(int timeStamp) m_lastEmission[i] = time;//jump over this time period without emitting, because it's outside continue; } - while(pt < time || m_emitLeft){ + while(pt < time || !m_burstQueue.isEmpty()){ ParticleData* datum = m_system->newDatum(gId2); - if(!datum){//skip this emission - if(m_emitLeft) - --m_emitLeft; - else - pt += particleRatio; - continue; + if(datum){//else, skip this emission + datum->e = this;//###useful? + ParticleVertex &p = datum->pv; + + // Particle timestamp + p.t = pt; + p.lifeSpan = + (m_particleDuration + + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) + / 1000.0; + + // Particle position + // Note that burst location doesn't get used for follow emitter + qreal followT = pt - d->pv.t; + qreal followT2 = followT * followT * 0.5; + qreal sizeOffset = d->pv.size/2;//TODO: Current size? As an option + //TODO: Set variations + //Subtract offset, because PS expects this in emitter coordinates + QRectF boundsRect(d->pv.x - offset.x() + d->pv.sx * followT + d->pv.ax * followT2 - m_emitterXVariation/2, + d->pv.y - offset.y() + d->pv.sy * followT + d->pv.ay * followT2 - m_emitterYVariation/2, + m_emitterXVariation, + m_emitterYVariation); + // QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset, + // d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset, + // sizeOffset*2, + // sizeOffset*2); + + ParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder; + const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect); + p.x = newPos.x(); + p.y = newPos.y(); + + // Particle speed + const QPointF &speed = m_speed->sample(newPos); + p.sx = speed.x(); + p.sy = speed.y(); + + // Particle acceleration + const QPointF &accel = m_acceleration->sample(newPos); + p.ax = accel.x(); + p.ay = accel.y(); + + // Particle size + float sizeVariation = -m_particleSizeVariation + + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; + + float size = qMax((qreal)0.0, m_particleSize + sizeVariation); + float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation); + + p.size = size * float(m_emitting); + p.endSize = endSize * float(m_emitting); + + m_system->emitParticle(datum); } - datum->e = this;//###useful? - ParticleVertex &p = datum->pv; - - // Particle timestamp - p.t = pt; - p.lifeSpan = - (m_particleDuration - + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) - / 1000.0; - - // Particle position - qreal followT = pt - d->pv.t; - qreal followT2 = followT * followT * 0.5; - qreal sizeOffset = d->pv.size/2;//TODO: Current size? As an option - //TODO: Set variations - //Subtract offset, because PS expects this in emitter coordinates - QRectF boundsRect(d->pv.x - offset.x() + d->pv.sx * followT + d->pv.ax * followT2 - m_emitterXVariation/2, - d->pv.y - offset.y() + d->pv.sy * followT + d->pv.ay * followT2 - m_emitterYVariation/2, - m_emitterXVariation, - m_emitterYVariation); -// QRectF boundsRect(d->pv.x + d->pv.sx * followT + d->pv.ax * followT2 + offset.x() - sizeOffset, -// d->pv.y + d->pv.sy * followT + d->pv.ay * followT2 + offset.y() - sizeOffset, -// sizeOffset*2, -// sizeOffset*2); - - ParticleExtruder* effectiveEmissionExtruder = m_emissionExtruder ? m_emissionExtruder : m_defaultEmissionExtruder; - const QPointF &newPos = effectiveEmissionExtruder->extrude(boundsRect); - p.x = newPos.x(); - p.y = newPos.y(); - - // Particle speed - const QPointF &speed = m_speed->sample(newPos); - p.sx = speed.x(); - p.sy = speed.y(); - - // Particle acceleration - const QPointF &accel = m_acceleration->sample(newPos); - p.ax = accel.x(); - p.ay = accel.y(); - - // Particle size - float sizeVariation = -m_particleSizeVariation - + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; - - float size = qMax((qreal)0.0, m_particleSize + sizeVariation); - float endSize = qMax((qreal)0.0, sizeAtEnd + sizeVariation); - - p.size = size * float(m_emitting); - p.endSize = endSize * float(m_emitting); - - if(m_emitLeft) - --m_emitLeft; - else + if(!m_burstQueue.isEmpty()){ + m_burstQueue.first().first--; + if(m_burstQueue.first().first <= 0) + m_burstQueue.pop_front(); + }else{ pt += particleRatio; - m_system->emitParticle(datum); + } } m_lastEmission[i] = pt; } diff --git a/src/imports/particles/killaffector.cpp b/src/imports/particles/killaffector.cpp index 1af7791..c98a2f4 100644 --- a/src/imports/particles/killaffector.cpp +++ b/src/imports/particles/killaffector.cpp @@ -51,7 +51,9 @@ KillAffector::KillAffector(QSGItem *parent) : bool KillAffector::affectParticle(ParticleData *d, qreal dt) { Q_UNUSED(dt); - d->pv.t -= d->pv.lifeSpan; - return true; + if(d->stillAlive()){ + d->pv.t -= d->pv.lifeSpan + 1; + return true; + } } QT_END_NAMESPACE diff --git a/src/imports/particles/particleemitter.cpp b/src/imports/particles/particleemitter.cpp index f490ed6..dd7d737 100644 --- a/src/imports/particles/particleemitter.cpp +++ b/src/imports/particles/particleemitter.cpp @@ -57,7 +57,6 @@ ParticleEmitter::ParticleEmitter(QSGItem *parent) : , m_particleSizeVariation(0) , m_maxParticleCount(-1) , m_burstLeft(0) - , m_emitLeft(0) { //TODO: Reset speed/acc back to null vector? Or allow null pointer? @@ -117,7 +116,7 @@ void ParticleEmitter::burst(int num) { if(!particleCount()) qWarning() << "burst called on an emitter with a particle count of zero"; - m_emitLeft += num; + m_burstQueue << qMakePair(num, QPointF(x(), y())); } void ParticleEmitter::setMaxParticleCount(int arg) diff --git a/src/imports/particles/particleemitter.h b/src/imports/particles/particleemitter.h index 61994e5..e272ae5 100644 --- a/src/imports/particles/particleemitter.h +++ b/src/imports/particles/particleemitter.h @@ -48,6 +48,9 @@ #include "particleextruder.h" #include "varyingvector.h" +#include +#include +#include QT_BEGIN_HEADER QT_BEGIN_NAMESPACE @@ -287,8 +290,8 @@ protected: qreal m_particleEndSize; qreal m_particleSizeVariation; - int m_burstLeft; - int m_emitLeft; + int m_burstLeft;//TODO: Rename to pulse + QList > m_burstQueue; int m_maxParticleCount; private: VaryingVector m_nullVector; diff --git a/src/imports/particles/trailsemitter.cpp b/src/imports/particles/trailsemitter.cpp index 2355670..41635a4 100644 --- a/src/imports/particles/trailsemitter.cpp +++ b/src/imports/particles/trailsemitter.cpp @@ -72,7 +72,7 @@ void TrailsEmitter::emitWindow(int timeStamp) { if (m_system == 0) return; - if((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && !m_emitLeft){ + if((!m_emitting || !m_particlesPerSecond)&& !m_burstLeft && m_burstQueue.isEmpty()){ m_reset_last = true; return; } @@ -92,6 +92,7 @@ void TrailsEmitter::emitWindow(int timeStamp) m_burstLeft = 0; } } + qreal time = timeStamp / 1000.; qreal particleRatio = 1. / m_particlesPerSecond; @@ -116,71 +117,76 @@ void TrailsEmitter::emitWindow(int timeStamp) qreal sizeAtEnd = m_particleEndSize >= 0 ? m_particleEndSize : m_particleSize; qreal emitter_x_offset = m_last_emitter.x() - x(); qreal emitter_y_offset = m_last_emitter.y() - y(); - while (pt < time || m_emitLeft) { + if(!m_burstQueue.isEmpty() && !m_burstLeft && !m_emitting)//'outside time' emissions only + pt = time; + while (pt < time || !m_burstQueue.isEmpty()) { //int pos = m_last_particle % m_particle_count; ParticleData* datum = m_system->newDatum(m_system->m_groupIds[m_particle]); - if(!datum){//skip this emission - if(!m_emitLeft) - pt += particleRatio; - else - --m_emitLeft; - continue; + if(datum){//actually emit(otherwise we've been asked to skip this one) + datum->e = this;//###useful? + ParticleVertex &p = datum->pv; + qreal t = 1 - (pt - opt) / dt; + qreal vx = + - 2 * ax * (1 - t) + + 2 * bx * (1 - 2 * t) + + 2 * cx * t; + qreal vy = + - 2 * ay * (1 - t) + + 2 * by * (1 - 2 * t) + + 2 * cy * t; + + + // Particle timestamp + p.t = pt; + p.lifeSpan = //TODO:Promote to base class? + (m_particleDuration + + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) + / 1000.0; + + // Particle position + QRectF boundsRect; + if(!m_burstQueue.isEmpty()){ + boundsRect = QRectF(m_burstQueue.first().second.x() - x(), m_burstQueue.first().second.y() - y(), + width(), height()); + } else { + boundsRect = QRectF(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt + , width(), height()); + } + QPointF newPos = effectiveExtruder()->extrude(boundsRect); + p.x = newPos.x(); + p.y = newPos.y(); + + // Particle speed + const QPointF &speed = m_speed->sample(newPos); + p.sx = speed.x() + + m_speed_from_movement * vx; + p.sy = speed.y() + + m_speed_from_movement * vy; + + // Particle acceleration + const QPointF &accel = m_acceleration->sample(newPos); + p.ax = accel.x(); + p.ay = accel.y(); + + // Particle size + float sizeVariation = -m_particleSizeVariation + + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; + + float size = qMax((qreal)0.0 , m_particleSize + sizeVariation); + float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation); + + p.size = size;// * float(m_emitting); + p.endSize = endSize;// * float(m_emitting); + + m_system->emitParticle(datum); } - datum->e = this;//###useful? - ParticleVertex &p = datum->pv; - qreal t = 1 - (pt - opt) / dt; - qreal vx = - - 2 * ax * (1 - t) - + 2 * bx * (1 - 2 * t) - + 2 * cx * t; - qreal vy = - - 2 * ay * (1 - t) - + 2 * by * (1 - 2 * t) - + 2 * cy * t; - - - // Particle timestamp - p.t = pt; - p.lifeSpan = //TODO:Promote to base class? - (m_particleDuration - + ((rand() % ((m_particleDurationVariation*2) + 1)) - m_particleDurationVariation)) - / 1000.0; - - // Particle position - QRectF boundsRect(emitter_x_offset + dex * (pt - opt) / dt, emitter_y_offset + dey * (pt - opt) / dt - , width(), height()); - QPointF newPos = effectiveExtruder()->extrude(boundsRect); - p.x = newPos.x(); - p.y = newPos.y(); - - // Particle speed - const QPointF &speed = m_speed->sample(newPos); - p.sx = speed.x() - + m_speed_from_movement * vx; - p.sy = speed.y() - + m_speed_from_movement * vy; - - // Particle acceleration - const QPointF &accel = m_acceleration->sample(newPos); - p.ax = accel.x(); - p.ay = accel.y(); - - // Particle size - float sizeVariation = -m_particleSizeVariation - + rand() / float(RAND_MAX) * m_particleSizeVariation * 2; - - float size = qMax((qreal)0.0 , m_particleSize + sizeVariation); - float endSize = qMax((qreal)0.0 , sizeAtEnd + sizeVariation); - - p.size = size;// * float(m_emitting); - p.endSize = endSize;// * float(m_emitting); - - if(!m_emitLeft) + if(m_burstQueue.isEmpty()){ pt += particleRatio; - else - --m_emitLeft; - - m_system->emitParticle(datum); + }else{ + m_burstQueue.first().first--; + if(m_burstQueue.first().first <= 0) + m_burstQueue.pop_front(); + } } m_last_emission = pt; -- 2.7.4