Add grid-based death pulse visual effect for enemies
This commit is contained in:
parent
802f11430c
commit
e0a6e6d116
|
|
@ -1,6 +1,7 @@
|
|||
const HP_BAR_WIDTH = 30;
|
||||
const HP_BAR_HEIGHT = 4;
|
||||
const HP_BAR_OFFSET_Y = -30;
|
||||
const GRID = 80;
|
||||
|
||||
export class BaseEnemy {
|
||||
constructor(scene, x, y, player, config) {
|
||||
|
|
@ -120,6 +121,36 @@ export class BaseEnemy {
|
|||
this._checkContact(delta);
|
||||
}
|
||||
|
||||
_gridDeathPulse() {
|
||||
if (!this._deathPulseColor || !this.scene._pulseEffects) return;
|
||||
const scene = this.scene;
|
||||
const W = scene.scale.width;
|
||||
const H = scene.scale.height;
|
||||
const col = Math.floor(this.x / GRID);
|
||||
const row = Math.floor(this.y / GRID);
|
||||
const color = this._deathPulseColor;
|
||||
|
||||
const makeTile = (c, r, alpha) => {
|
||||
if (c < 0 || r < 0 || c * GRID >= W || r * GRID >= H) return null;
|
||||
return scene.add.rectangle(
|
||||
c * GRID + GRID / 2, r * GRID + GRID / 2,
|
||||
GRID, GRID, color, alpha,
|
||||
).setDepth(2);
|
||||
};
|
||||
|
||||
const center = makeTile(col, row, 0.55);
|
||||
const adjacents = [];
|
||||
[[-1, 0], [1, 0], [0, -1], [0, 1]].forEach(([dc, dr]) => {
|
||||
const t = makeTile(col + dc, row + dr, 0.38);
|
||||
if (t) { t.setVisible(false); adjacents.push(t); }
|
||||
});
|
||||
|
||||
scene._pulseEffects.push({
|
||||
center, adjacents, elapsed: 0, adjSpawned: false,
|
||||
ADJ_MS: 80, FADE_MS: 120, END_MS: 400,
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.sprite?.destroy();
|
||||
this._hpBg?.destroy();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
import { BaseEnemy } from './BaseEnemy.js';
|
||||
|
||||
const GRID = 80;
|
||||
|
||||
export class ChaseEnemy extends BaseEnemy {
|
||||
constructor(scene, x, y, player) {
|
||||
super(scene, x, y, player, {
|
||||
|
|
@ -20,4 +22,45 @@ export class ChaseEnemy extends BaseEnemy {
|
|||
Math.sin(angle) * this.speed
|
||||
);
|
||||
}
|
||||
|
||||
_die() {
|
||||
this._gridDeathPulse(this.x, this.y);
|
||||
super._die();
|
||||
}
|
||||
|
||||
_gridDeathPulse(px, py) {
|
||||
const scene = this.scene;
|
||||
const W = scene.scale.width;
|
||||
const H = scene.scale.height;
|
||||
const col = Math.floor(px / GRID);
|
||||
const row = Math.floor(py / GRID);
|
||||
|
||||
const makeTile = (c, r, alpha) => {
|
||||
if (c < 0 || r < 0 || c * GRID >= W || r * GRID >= H) return null;
|
||||
return scene.add.rectangle(
|
||||
c * GRID + GRID / 2,
|
||||
r * GRID + GRID / 2,
|
||||
GRID, GRID, 0x00ff44, alpha,
|
||||
).setDepth(2);
|
||||
};
|
||||
|
||||
const center = makeTile(col, row, 0.55);
|
||||
|
||||
// Pre-create adjacent tiles but hide them until ADJ_MS elapses
|
||||
const adjacents = [];
|
||||
[[-1, 0], [1, 0], [0, -1], [0, 1]].forEach(([dc, dr]) => {
|
||||
const t = makeTile(col + dc, row + dr, 0.38);
|
||||
if (t) { t.setVisible(false); adjacents.push(t); }
|
||||
});
|
||||
|
||||
scene._pulseEffects.push({
|
||||
center,
|
||||
adjacents,
|
||||
elapsed: 0,
|
||||
adjSpawned: false,
|
||||
ADJ_MS: 80,
|
||||
FADE_MS: 120,
|
||||
END_MS: 400,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@ export class GameScene extends Phaser.Scene {
|
|||
this._levelUpPending = false;
|
||||
this._frozen = false;
|
||||
this._waitingForExit = false;
|
||||
this._pulseEffects = [];
|
||||
|
||||
this.events.on('zone-waves-complete', () => this._startZoneExit());
|
||||
|
||||
|
|
@ -117,10 +118,35 @@ export class GameScene extends Phaser.Scene {
|
|||
this._checkBulletHits();
|
||||
this._checkEnemyProjectileHits();
|
||||
this._pruneEnemyProjectiles();
|
||||
this._updatePulseEffects(delta);
|
||||
|
||||
if (this._waitingForExit) this._checkPlayerExit();
|
||||
}
|
||||
|
||||
_updatePulseEffects(delta) {
|
||||
this._pulseEffects = this._pulseEffects.filter(effect => {
|
||||
effect.elapsed += delta;
|
||||
|
||||
if (!effect.adjSpawned && effect.elapsed >= effect.ADJ_MS) {
|
||||
effect.adjSpawned = true;
|
||||
effect.adjacents.forEach(t => { if (t?.active) t.setVisible(true); });
|
||||
}
|
||||
|
||||
if (effect.elapsed >= effect.FADE_MS) {
|
||||
const progress = Math.min(1, (effect.elapsed - effect.FADE_MS) / (effect.END_MS - effect.FADE_MS));
|
||||
if (effect.center?.active) effect.center.alpha = Math.max(0, 0.55 * (1 - progress));
|
||||
effect.adjacents.forEach(t => { if (t?.active) t.alpha = Math.max(0, 0.38 * (1 - progress)); });
|
||||
}
|
||||
|
||||
if (effect.elapsed >= effect.END_MS) {
|
||||
if (effect.center?.active) effect.center.destroy();
|
||||
effect.adjacents.forEach(t => { if (t?.active) t.destroy(); });
|
||||
return false; // remove from array
|
||||
}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
_checkBulletHits() {
|
||||
const bullets = this.player.bullets.getChildren();
|
||||
const enemies = this.waveManager.enemies;
|
||||
|
|
@ -339,5 +365,6 @@ export class GameScene extends Phaser.Scene {
|
|||
this.waveManager?.reset();
|
||||
this.hud?.destroy();
|
||||
this._enemyProjectiles = [];
|
||||
this._pulseEffects = [];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue