当一个生命结束时,所有粒子都会被删除

All particles get deleted when one life ends

https://jsfiddle.net/zwkdf0cg/12/

class Emitter {
    constructor(settings) {
        for (let key in settings) {
            this[key] = settings[key];
        }
        this.particle = undefined;
        this.parts = [];
    }

    grab_parts(particle_settings) {
        this.particle = particle_settings;
        return this.particle;
    }

    load_parts() {
        if (this.counters.rate >= this.rate) {
            for (let i = 0; i < this.particles.max; i++) {
                this.parts.push(new Particle(this.particle));
            }
            this.counters.rate = 0;
        }
        this.counters.rate += this.timer();
    }

    draw_parts() {
        for (let i = 0; i < this.parts.length; i++) {
            let p = this.parts[i];
            let can = this.canvas;
            let con = this.context;

            con.beginPath();
            con.arc(p.x, p.y, p.radius, 0, 2 * Math.PI);
            let gradient = con.createRadialGradient(p.x, p.y, p.radius, p.x, p.y, 0);
            gradient.addColorStop(0,'hsla(20, 80%, 50%, 0)');
            gradient.addColorStop(1,'hsla(20, 80%, 50%, 0.5)');
            con.fillStyle = gradient;
            con.fill();            
        }
    }

    update_parts() {
        let can = this.canvas;
        let con = this.context;
        for (let i = 0; i < this.parts.length; i++) {
            let p = this.parts[i];
            if (p.x < -5 || p.x > can.width || p.y < -5 || p.y > can.height || p.counters.life < 0) {
                let s = this.parts.splice(i, 1);
            } else {
                this.parts[i].update();
            }
        }        
    } 
}



class Particle {
    constructor(settings) {
        for (let key in settings) {
            this[key] = settings[key];
        }
        this.initialize = {
            angle: false
        }
        this.life.range = number_range(this.life.min, this.life.max);
        this.counters.life = this.life.range;
    }

    update() {
        if (!this.initialize.angle) {
            this.angle = radians(number_range(160, 180));
            this.initialize.angle = true;
        }
        this.x += 1 * Math.cos(this.angle);
        this.y += 1 * Math.sin(this.angle);

        this.counters.life -= this.timer();        
    }
}

每次创建粒子时,我都会将粒子的寿命设置为 2 到 8 之间的数字。在粒子的 update() 方法中,从发射器的 update_parts() 方法调用,它的生命计数器被它的 timer() 属性 减少,这是自上次更新以来经过的 returns 时间。发射器的 update_parts() 方法有一个条件,如果粒子超出范围或生命 < 0,它将拼接来自发射器的 parts[] 数组的粒子。每当单个粒子的生命 < 0 时,所有粒子在屏幕上拼接,我不明白为什么。我尝试反转数组的迭代,创建一个仅包含活粒子的新数组并将发射器的 parts[] 数组分配给它,标记死粒子并创建一个新函数以在 update_parts( ) 被称为随机调整。我在将 particle_settings 对象传递给粒子的构造函数时遇到了一些问题,但我不知道它们是否相关。 ET phone 家。

您在迭代的数组上调用 .splice(),这是个坏主意; splice() changes the size of the array it's called on 所以你的循环测试条件不会总是像你认为的那样工作。如果将 update_parts() 中的 for() 循环替换为以下内容,会发生什么情况:

this.parts = this.parts.filter(function(part) {
  // filter out the ones we don't want...
  return !(p.x < -5 || p.x > can.width || p.y < -5 || p.y > can.height || p.counters.life < 0);
}).forEach(function(part) {
  // ...and update the rest
  part.update();
});

这段代码是罪魁祸首:

for (let key in settings) {
    this[key] = settings[key];
}

当您在那里传递 counters 对象时,它不会被复制,而是在实例之间共享。

改为检查 updated version using lodashcloneDeep

_.assign(this, _.cloneDeep(settings));

_.assign 将属性分配给 this 类似于您的原始代码。
_.cloneDeep 执行 settings 对象的深拷贝。