109 lines
2.9 KiB
JavaScript
109 lines
2.9 KiB
JavaScript
import { Vector2D } from './Vector2D.js';
|
|
|
|
const MAX_PARTICLES = 450;
|
|
|
|
export class ParticleSystem {
|
|
constructor() {
|
|
this.particles = [];
|
|
}
|
|
|
|
burst(
|
|
x,
|
|
y,
|
|
{
|
|
count = 12,
|
|
speed = 150,
|
|
direction = 0,
|
|
spread = Math.PI * 2,
|
|
life = 0.4,
|
|
size = 4,
|
|
color = [1, 1, 1, 1],
|
|
gravity = 0,
|
|
drag = 0,
|
|
shape = 'square',
|
|
additive = false,
|
|
endSize = null,
|
|
spin = 0,
|
|
} = {},
|
|
) {
|
|
for (let i = 0; i < count; i++) {
|
|
if (this.particles.length >= MAX_PARTICLES) return;
|
|
|
|
const angle = direction + (Math.random() - 0.5) * spread;
|
|
const magnitude = speed * (0.4 + Math.random() * 0.8);
|
|
const velocity = new Vector2D(Math.cos(angle), Math.sin(angle)).mulS(magnitude);
|
|
const lifetime = life * (0.6 + Math.random() * 0.6);
|
|
const startSize = size * (0.6 + Math.random() * 0.8);
|
|
|
|
this.particles.push({
|
|
pos: new Vector2D(x, y),
|
|
velocity,
|
|
gravity,
|
|
drag,
|
|
life: lifetime,
|
|
maxLife: lifetime,
|
|
size: startSize,
|
|
endSize: endSize === null ? startSize * 0.15 : endSize * (0.6 + Math.random() * 0.8),
|
|
color: [...color],
|
|
shape,
|
|
additive,
|
|
angle: Math.random() * Math.PI * 2,
|
|
spin: (Math.random() - 0.5) * (spin * 2),
|
|
});
|
|
}
|
|
}
|
|
|
|
update(dt) {
|
|
const { particles } = this;
|
|
for (let i = particles.length - 1; i >= 0; i--) {
|
|
const particle = particles[i];
|
|
particle.pos = particle.velocity.mulS(dt).addV(particle.pos);
|
|
particle.velocity.y += particle.gravity * dt;
|
|
if (particle.drag > 0) {
|
|
particle.velocity = particle.velocity.mulS(Math.max(0, 1 - particle.drag * dt));
|
|
}
|
|
particle.angle += particle.spin * dt;
|
|
particle.life -= dt;
|
|
if (particle.life <= 0) {
|
|
particles.splice(i, 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
draw(renderer) {
|
|
const additive = this.particles.filter((particle) => particle.additive);
|
|
const normal = this.particles.filter((particle) => !particle.additive);
|
|
|
|
if (additive.length > 0) renderer.setBlendMode('additive');
|
|
for (const particle of additive) this._drawParticle(renderer, particle);
|
|
if (additive.length > 0) renderer.setBlendMode('normal');
|
|
|
|
for (const particle of normal) this._drawParticle(renderer, particle);
|
|
}
|
|
|
|
_drawParticle(renderer, particle) {
|
|
const alpha = Math.max(0, particle.life / particle.maxLife);
|
|
const progress = 1 - alpha;
|
|
const size = particle.size + (particle.endSize - particle.size) * progress;
|
|
const color = [
|
|
particle.color[0],
|
|
particle.color[1],
|
|
particle.color[2],
|
|
particle.color[3] * alpha,
|
|
];
|
|
const texture = particle.shape === 'glow' ? renderer.glowTexture : renderer.whiteTexture;
|
|
renderer.drawTexture(
|
|
texture,
|
|
particle.pos.x - size / 2,
|
|
particle.pos.y - size / 2,
|
|
size,
|
|
size,
|
|
color,
|
|
particle.angle,
|
|
);
|
|
}
|
|
|
|
clear() {
|
|
this.particles.length = 0;
|
|
}
|
|
} |