Particles
A particle system spawns short-lived sprites with velocity, acceleration, and a lifetime — perfect for fire, smoke, dust, blood, spell effects. The trick is pooling: never allocate per particle in the hot path.
A pooled particle system
EXAMPLE
// One emitter, hundreds of particles, zero per-frame allocation
class Particle {
constructor() {
this.x = 0; this.y = 0;
this.vx = 0; this.vy = 0;
this.life = 0; this.maxLife = 0;
this.size = 0; this.colour = '#fff';
this.alive = false;
}
}
class ParticleSystem {
constructor(capacity = 1000) {
this.pool = Array.from({ length: capacity }, () => new Particle());
this.next = 0;
}
emit({ x, y, vx, vy, life, size, colour }) {
const p = this.pool[this.next];
this.next = (this.next + 1) % this.pool.length;
p.x = x; p.y = y;
p.vx = vx; p.vy = vy;
p.life = life; p.maxLife = life;
p.size = size; p.colour = colour;
p.alive = true;
}
update(dt, gravity = 800) {
for (const p of this.pool) {
if (!p.alive) continue;
p.vy += gravity * dt;
p.x += p.vx * dt;
p.y += p.vy * dt;
p.life -= dt;
if (p.life <= 0) p.alive = false;
}
}
render(ctx) {
for (const p of this.pool) {
if (!p.alive) continue;
const alpha = p.life / p.maxLife;
ctx.globalAlpha = alpha;
ctx.fillStyle = p.colour;
ctx.fillRect(p.x - p.size / 2, p.y - p.size / 2, p.size, p.size);
}
ctx.globalAlpha = 1;
}
}
// Emit on demand
function explode(particles, x, y) {
for (let i = 0; i < 60; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 200 + Math.random() * 300;
particles.emit({
x, y,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
life: 0.6 + Math.random() * 0.4,
size: 2 + Math.random() * 4,
colour: ['#ff5151', '#ffd23f', '#fff'][Math.floor(Math.random() * 3)],
});
}
}
Why it matters
Pool particles. Allocating a new {x, y, vx, vy} per spawn looks innocent and is the #1 reason 60fps drops to 30 when explosions happen. Same trick applies to bullets and enemies.
Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.
Example
Example
// Pool short-lived sprites with velocity + lifetime to fake fire, dust, explosions.
class Particle {
constructor(x, y, vx, vy, life) { Object.assign(this, { x, y, vx, vy, life }); }
update(dt) { this.x += this.vx*dt; this.y += this.vy*dt; this.life -= dt; }
}
Try it Yourself »
Discussion
Loading…