pixijs / particle-emitter

A particle system for PixiJS
http://pixijs.io/particle-emitter/docs
MIT License
786 stars 124 forks source link

PathParticle throws "TypeError: this.next is null" when speed has no interpolation #129

Closed MxAshUp closed 4 years ago

MxAshUp commented 4 years ago

Background It took me a while to get the ParticlePath working, but following the example code I finally got it, with one exception: when I had the speed set to no interpolation (ie start speed = end speed) I got an error "TypeError: this.next is null".

How to reproduce

  var emitter = new Emitter(
    container,
    [sprite],
    {
      ...
      "speed": {
        "start": 100,
        "end": 100,
        "minimumSpeedMultiplier": 1
      },
      "extraData": {
        "path":"sin(x/10)*20"
      },
    });

    emitter.particleConstructor = PathParticle;

Solution I've debugged the code enough to understand the cause. In PathParticle here: https://github.com/pixijs/pixi-particles/blob/master/src/PathParticle.ts#L153, the code assumes speedList needs to be interpolated. I think the solution involves first checking if this._doSpeed is true. If I understand PathParticle correctly the fix should look something like this:

if(this._doSpeed) {
  const speed = this.speedList.interpolate(lerp) * this.speedMultiplier;
  this.movement += speed * delta;
} else {
  const speed = ParticleUtils.length(this.velocity);
  this.movement += speed * delta;
}

EDIT: Workaround For anyone seeing this issue and needing a workaround (providing this isn't closed yet), I recommend setting speed start and end to nearly the same value, for example:

      "speed": {
        "start": 100,
        "end": 100.0001,
        "minimumSpeedMultiplier": 1
      },

I'll get a PR started

MxAshUp commented 4 years ago

I also noticed that PathParticle ignores acceleration. But this may be expected behavior. However adding acceleration support for PathParticle could be easy (this is tested and works):

// PathParticle.update()
// ...
if(this._doSpeed) {
    const speed = this.speedList.interpolate(lerp) * this.speedMultiplier;
    this.movement += speed * delta;
} else {
    // Adapted from Particle.update()
    if (this._doAcceleration) {
        this.velocity.x += this.acceleration.x * delta;
        this.velocity.y += this.acceleration.y * delta;
        if (this.maxSpeed) {
            var currentSpeed = ParticleUtils.length(this.velocity);
            if (currentSpeed > this.maxSpeed) {
                ParticleUtils.scaleBy(this.velocity, this.maxSpeed / currentSpeed);
            }
        }
    }

    const speed = ParticleUtils.length(this.velocity);
    this.movement += speed * delta;
}
// ...

Maybe open a feature request for it?

andrewstart commented 4 years ago

Ignoring acceleration is intentional - PathParticles are supposed to move in an exact path, and being affected by gravity/wind would interfere with that. Merely changing this.movement would be different behavior than what acceleration does to normal particles, and basically duplicates what interpolating speed values does.