/** * Explosion.js * Simple explosion effect using frame-based animation. * Managed via object pool for performance. */ class Explosion { constructor() { this.x = 0; this.y = 0; this.alive = false; this.size = 0; this.maxSize = 30; this._timer = 0; this._duration = 0.3; // seconds this._phase = 0; // 0 to 1 this._isBig = false; // big explosion for tank destruction } /** * Initialize the explosion. * @param {number} x - Center X. * @param {number} y - Center Y. * @param {boolean} [isBig=false] - Whether this is a large explosion (tank death). */ init(x, y, isBig = false) { this.x = x; this.y = y; this.alive = true; this._timer = 0; this._phase = 0; this._isBig = isBig; this.maxSize = isBig ? 50 : 25; this._duration = isBig ? 0.5 : 0.3; } /** * Update explosion animation. * @param {number} dt - Delta time in seconds. */ update(dt) { if (!this.alive) return; this._timer += dt; this._phase = this._timer / this._duration; if (this._phase >= 1) { this.alive = false; return; } // Size grows then shrinks if (this._phase < 0.4) { this.size = this.maxSize * (this._phase / 0.4); } else { this.size = this.maxSize * (1 - (this._phase - 0.4) / 0.6); } } /** * Render the explosion. * @param {CanvasRenderingContext2D} ctx */ render(ctx) { if (!this.alive) return; ctx.save(); const alpha = 1 - this._phase * 0.5; ctx.globalAlpha = alpha; // Outer glow if (this._isBig) { ctx.fillStyle = '#FF4500'; ctx.beginPath(); ctx.arc(this.x, this.y, this.size * 1.2, 0, Math.PI * 2); ctx.fill(); } // Main explosion ctx.fillStyle = '#FF8C00'; ctx.beginPath(); ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2); ctx.fill(); // Inner bright core ctx.fillStyle = '#FFFF00'; ctx.beginPath(); ctx.arc(this.x, this.y, this.size * 0.5, 0, Math.PI * 2); ctx.fill(); // White center flash (early phase only) if (this._phase < 0.3) { ctx.fillStyle = '#FFFFFF'; ctx.beginPath(); ctx.arc(this.x, this.y, this.size * 0.2, 0, Math.PI * 2); ctx.fill(); } ctx.restore(); } } module.exports = Explosion;