1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-06-08 17:42:05 +00:00

Improve particle spawning behavior; small cleanup

Apparently there was an interpolation scheme in place to spawn
quickly-spawning (ie more than 1 per frame) particles along a line
interpolated between the previous and current position,
but the math was incorrect and it always ended up spawning all
particles on the same spot.
This commit is contained in:
fgenesis 2025-02-05 04:54:37 +01:00
parent 7b442174c8
commit 68c29a3fc9
3 changed files with 36 additions and 23 deletions

View file

@ -41,7 +41,6 @@ SpawnParticleData::SpawnParticleData()
color = Vector(1,1,1); color = Vector(1,1,1);
alpha = 1; alpha = 1;
randomSpawnRadius = 0; randomSpawnRadius = 0;
lastDTDifference = 0;
randomRotationRange = 0; randomRotationRange = 0;
number = 1; number = 1;
@ -52,7 +51,7 @@ SpawnParticleData::SpawnParticleData()
randomVelocityMagnitude = 0; randomVelocityMagnitude = 0;
copyParentRotation = 0; copyParentRotation = 0;
justOne = didOne = false; justOne = false;
flipH = flipV = 0; flipH = flipV = 0;
spawnTimeOffset = 0; spawnTimeOffset = 0;
pauseLevel = 0; pauseLevel = 0;
@ -80,7 +79,7 @@ void Emitter::destroy()
} }
void Emitter::spawnParticle(float perc) Particle *Emitter::spawnParticle(const Vector& spawnpos)
{ {
Particle *p = particleManager->getFreeParticle(this); Particle *p = particleManager->getFreeParticle(this);
@ -101,7 +100,7 @@ void Emitter::spawnParticle(float perc)
p->rot = data.rotation; p->rot = data.rotation;
p->pos = lastSpawn + ((currentSpawn - lastSpawn) * perc); p->pos = spawnpos;
float finalRadius = data.randomSpawnRadius + rng.f01() * data.randomSpawnRadiusRange; float finalRadius = data.randomSpawnRadius + rng.f01() * data.randomSpawnRadiusRange;
@ -135,6 +134,8 @@ void Emitter::spawnParticle(float perc)
{ {
p->rot.z = getAbsoluteRotation().z; p->rot.z = getAbsoluteRotation().z;
} }
return p;
} }
float Emitter::randAngle() float Emitter::randAngle()
@ -162,27 +163,26 @@ void Emitter::onUpdate(float dt)
data.spawnTimeOffset -= dt; data.spawnTimeOffset -= dt;
if (data.spawnTimeOffset > 0) if (data.spawnTimeOffset > 0)
return; return;
lastSpawn = getSpawnPosition();
} }
int spawnCount; int spawnCount = 0;
float spawnPerc; float spawnPerc;
if (data.justOne) if (data.justOne)
{ {
if (data.didOne) if (!didOne)
spawnCount = 0;
else
spawnCount = data.justOne; spawnCount = data.justOne;
spawnPerc = 1; spawnPerc = 0; // Spawn all of them in the same spot
data.didOne = 1; didOne = true;
} }
else else
{ {
float num = data.number.x * dt; float num = data.number.x * dt;
num += data.lastDTDifference; num += lastDTDifference;
spawnCount = int(num); spawnCount = int(num);
data.lastDTDifference = num - float(spawnCount); lastDTDifference = num - float(spawnCount);
if (spawnCount > 0) if (spawnCount > 0)
spawnPerc = 1.0f / float(spawnCount); spawnPerc = 1.0f / num;
} }
if (spawnCount > 0) if (spawnCount > 0)
@ -190,16 +190,23 @@ void Emitter::onUpdate(float dt)
// Avoid calling this until we know we actually need it for // Avoid calling this until we know we actually need it for
// generating a particle (it has to apply the matrix chain, // generating a particle (it has to apply the matrix chain,
// which is slow). // which is slow).
currentSpawn = getSpawnPosition(); const Vector currentSpawn = getSpawnPosition();
if (lastSpawn.isZero())
lastSpawn = currentSpawn;
for (; spawnCount > 0; spawnCount--) // Given the last spawn position and the new spawn position, interpolate as many particles
// along the line between both positions. Start at current and move back to prev.
// For convenience, 0 is the current pos and 1 is the prev. pos.
float percAccu = 0;
for(int i = 0; i < spawnCount; ++i)
{ {
spawnParticle(spawnPerc); spawnParticle(lerp(currentSpawn, lastSpawn, percAccu));
// This is unlikely to reach 1 perfectly, which is good since what is currently 1
// was 0 in the previous iteration, and that is known to be hit perfectly.
// This way we usually don't end up placing 2 particles in the same spot.
percAccu += spawnPerc;
} }
lastSpawn = currentSpawn; lastSpawn = currentSpawn;
} }
data.number.update(dt); data.number.update(dt);
@ -207,7 +214,8 @@ void Emitter::onUpdate(float dt)
void Emitter::start() void Emitter::start()
{ {
data.didOne = 0; didOne = false;
lastDTDifference = 0;
lastSpawn = getSpawnPosition(); lastSpawn = getSpawnPosition();
} }

View file

@ -44,7 +44,6 @@ struct SpawnParticleData
float randomSpawnRadius; float randomSpawnRadius;
Vector randomSpawnMod; Vector randomSpawnMod;
int randomSpawnRadiusRange; int randomSpawnRadiusRange;
bool didOne;
int justOne; int justOne;
int copyParentRotation, copyParentFlip; int copyParentRotation, copyParentFlip;
@ -58,7 +57,6 @@ struct SpawnParticleData
bool inheritColor; bool inheritColor;
bool inheritAlpha; bool inheritAlpha;
float lastDTDifference;
int influenced; int influenced;
std::string deathPrt; std::string deathPrt;
@ -120,9 +118,11 @@ public:
bool hasRot; // FIXME: this should be removed eventually bool hasRot; // FIXME: this should be removed eventually
protected: protected:
Vector currentSpawn, lastSpawn; Vector lastSpawn;
float lastDTDifference;
bool didOne;
void onRender(const RenderState& rs) const OVERRIDE; void onRender(const RenderState& rs) const OVERRIDE;
void spawnParticle(float perc=1); Particle *spawnParticle(const Vector& spawnpos);
void onUpdate(float dt) OVERRIDE; void onUpdate(float dt) OVERRIDE;
float randAngle(); float randAngle();

View file

@ -526,6 +526,11 @@ public:
Vector getRotatedVector(const Vector &vec, float rot); Vector getRotatedVector(const Vector &vec, float rot);
inline Vector lerp(const Vector &v1, const Vector &v2, float t)
{
return (v2-v1)*t+v1;
}
Vector lerp(const Vector &v1, const Vector &v2, float dt, int lerpType); Vector lerp(const Vector &v1, const Vector &v2, float dt, int lerpType);
#endif // BBGE_VECTOR_H #endif // BBGE_VECTOR_H