// ═══ particles.js ═══ // ============================================================ // PARTICLES.JS — Particles, floaters, damage numbers // ============================================================ const MAX_PARTICLES = 400; const MAX_FLOATERS = 40; function spawnParticle(x, y, color, vx, vy, life, radius, decay) { if (G.particles.length >= MAX_PARTICLES) return; G.particles.push({ x, y, color, vx, vy, life, radius, decay }); } function spawnParticleBurst(x, y, color, count) { const free = MAX_PARTICLES - G.particles.length; const actual = Math.min(count, free); for (let i = 0; i < actual; i++) { const angle = Math.random() * Math.PI * 2; const speed = 1 + Math.random() * 3.5; spawnParticle( x, y, color, Math.cos(angle) * speed, Math.sin(angle) * speed, 0.9 + Math.random() * 0.1, 2 + Math.random() * 4, 0.03 + Math.random() * 0.04 ); } } function spawnFloater(x, y, text, color, scale = 1.0) { if (G.floaters.length >= MAX_FLOATERS) return; G.floaters.push({ x, y, text, color, scale, life: 1, vy: -1.0 - Math.random() * 0.5, vx: (Math.random() - 0.5) * 0.8, }); } function updateParticles() { compactLiveArray(G.particles, p => { p.x += p.vx; p.y += p.vy; p.vx *= 0.91; p.vy *= 0.91; p.life -= p.decay; return p.life > 0; }); } function updateFloaters() { compactLiveArray(G.floaters, f => { f.x += f.vx; f.y += f.vy; f.life -= 0.018; return f.life > 0; }); }