Search code examples
javalibgdx

How can I start a LIBGDX particle effect mid way through?


Is it possible to start a particle effect mid way through? I have tried many variations of updating the particle effect/emitters upon initialisation. None of them seem to work. Has anyone managed to do this before? Thanks a lot!

    ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
    effect.setPosition(posnX,posnY);

    float value = 1.5f;

    for(ParticleEmitter e: effect.getEmitters()){
        e.update(value);
        value+=1.5f;
    }

The above code doesn't draw all of the particles, but it does seem to update the them somewhat. Once the initial effect is over, it resets and then it looks fine

EDIT: I've found a little bit of a hack by doing the following code snippet 5 times upon initialisation of the particle effect. Still interested to see if someone has a better solution

 p.getEmitters().get(0).addParticle();
 p.update(1);

Solution

  • I assume, that all emitters in your ParticleEffect have the same duration:

    ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
    effect.reset();
    effect.setPosition(posnX,posnY);
    
    //divide by 1000 to convert from ms to seconds
    float effectDuration = effect.getEmitters().first().duration / 1000f;
    float skipProgress = 0.5f;
    effect.update(skipProgress * effectDuration);
    

    Note, that if emitters have different duration, you probably would want to pick the max duration. Also, if your emitters have delays, you should take them into account too.

    Update

    This approach will not work as expected in case, when some of effect's properties change over time. So if you skip half of its duration, you don't take in account all changes that happened before. You just start from some state.

    For example, let's say effect has duration = 10, and its velocity is 100 for the first 4 seconds, and after that velocity is 0. If you call effect.update(5), i.e. just skip first 5 seconds, particles will have velocity = 0, they just won't "know", that they had to move for the first 4 seconds.

    So, I guess the only workaround here, is to update the effect with small steps in a loop, instead of just updating for half of its duration in one call:

    ParticleEffectPool.PooledEffect effect = particleEffectPool.obtain();
    effect.reset();
    effect.setPosition(posnX,posnY);
    
    //divide by 1000 to convert from ms to seconds
    float skipDuration = 0.5f * effect.getEmitters().first().duration / 1000f;
    //I guess, to reduce number of iterations in a loop, you can safely use 
    //a bit bigger stepDeltaTime, like 1 / 10f or bigger, but it depends on you effect;
    //here I just use standard frame duration
    final float stepDeltaTime = 1 / 60f;
    
    while (skipDuration > 0) {
        float dt = skipDuration < stepDeltaTime ? skipDuration : stepDeltaTime;
        effect.update(dt);
        skipDuration -= stepDeltaTime;
    }