"use strict"; const HullHitExplosionsFx = (function(){ const HullHitExplosionsFx = function(xgravity){ let shockwaves = []; let particles = []; this.add = (cell_x, cell_y) => { if(xgravity.audio){ xgravity.audio.play("hit_explosion"); } const particles_range = xgravity.settings.get("explosion_particles_range", null, [45, 75]); const spread_reach = xgravity.settings.get("explosion_particles_spread", null, 11.0); const base_shockwave_radius = xgravity.settings.get("explosion_shockwave_radius", null, 4.5); const min_p = Math.min(particles_range[0], particles_range[1]); const max_p = Math.max(particles_range[0], particles_range[1]); const count = Math.floor(min_p + Math.random() * (max_p - min_p + 1)); // Onda roja más grande shockwaves.push({ x : cell_x, y : cell_y, radius : 0.4, max_radius : base_shockwave_radius * 1.15, speed : 8.0, angle : Math.random() * Math.PI * 2, aspect_ratio : 0.42 + (Math.random() * 0.18), alpha : 1.0, color_rgb : "239, 68, 68" }); // Metralla naranja/roja/amarilla for(let i = 0; i < count; i++){ const angle = Math.random() * Math.PI * 2; const speed = (Math.random() * spread_reach) + 1.2; const life = (Math.random() * 0.38) + 0.28; const rim_rgb = Math.random() > 0.4 ? "239, 68, 68" : (Math.random() > 0.5 ? "249, 115, 22" : "251, 191, 36"); particles.push({ x : cell_x, y : cell_y, vx : Math.cos(angle) * speed, vy : Math.sin(angle) * speed, size : (Math.random() * 0.16) + 0.08, life : life, max_life : life, core_rgb : "255, 255, 255", rim_rgb : rim_rgb }); } }; this.update = (delta_time) => { for(let i = shockwaves.length - 1; i >= 0; i--){ const s = shockwaves[i]; s.radius += s.speed * delta_time; s.alpha = Math.max(0, 1.0 - (s.radius / s.max_radius)); if(s.radius >= s.max_radius){ shockwaves.splice(i, 1); } } for(let i = particles.length - 1; i >= 0; i--){ const p = particles[i]; p.life -= delta_time; if(p.life <= 0){ particles.splice(i, 1); continue; } p.x += p.vx * delta_time; p.y += p.vy * delta_time; p.vx *= 0.93; p.vy *= 0.93; } }; this.render = (ctx, cell_px, cx, cy) => { for(let i = 0; i < shockwaves.length; i++){ const s = shockwaves[i]; const px = cx + (s.x * cell_px); const py = cy + (s.y * cell_px); const r_px = s.radius * cell_px; ctx.save(); ctx.translate(px, py); ctx.rotate(s.angle); ctx.scale(1.0, s.aspect_ratio); ctx.lineWidth = cell_px * 0.14 * s.alpha; ctx.strokeStyle = `rgba(${s.color_rgb}, ${s.alpha * 0.85})`; ctx.beginPath(); ctx.arc(0, 0, r_px, 0, Math.PI * 2); ctx.stroke(); ctx.lineWidth = cell_px * 0.05 * s.alpha; ctx.strokeStyle = `rgba(255, 255, 255, ${s.alpha * 0.6})`; ctx.beginPath(); ctx.arc(0, 0, r_px * 0.82, 0, Math.PI * 2); ctx.stroke(); ctx.restore(); } for(let i = 0; i < particles.length; i++){ const p = particles[i]; const px = cx + (p.x * cell_px); const py = cy + (p.y * cell_px); const r_px = p.size * cell_px; const progress = Math.max(0, p.life / p.max_life); const grad = ctx.createRadialGradient(px, py, 0, px, py, r_px); grad.addColorStop(0.0, `rgba(${p.core_rgb}, ${progress})`); grad.addColorStop(0.45, `rgba(${p.rim_rgb}, ${progress * 0.75})`); grad.addColorStop(1.0, `rgba(${p.rim_rgb}, 0.0)`); ctx.fillStyle = grad; ctx.beginPath(); ctx.arc(px, py, r_px, 0, Math.PI * 2); ctx.fill(); } }; this.reset = () => { shockwaves = []; particles = []; }; }; return HullHitExplosionsFx; })();