Add player death mechanics with enemy freeze, projectile cleanup, and event-driven state management
This commit is contained in:
parent
04ecdcccc3
commit
840f6788ab
|
|
@ -188,6 +188,7 @@ export class Player {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.scene.sound.play('sfx-death', { volume: 0.6 });
|
this.scene.sound.play('sfx-death', { volume: 0.6 });
|
||||||
|
this.scene.events.emit('player-died');
|
||||||
|
|
||||||
this.hp = this.stats.maxHp;
|
this.hp = this.stats.maxHp;
|
||||||
this.invincible = true;
|
this.invincible = true;
|
||||||
|
|
@ -229,6 +230,7 @@ export class Player {
|
||||||
onComplete: () => {
|
onComplete: () => {
|
||||||
this.sprite.setAlpha(1);
|
this.sprite.setAlpha(1);
|
||||||
this.invincible = false;
|
this.invincible = false;
|
||||||
|
this.scene.events.emit('player-respawned');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -85,6 +85,8 @@ export class GameScene extends Phaser.Scene {
|
||||||
|
|
||||||
this.events.on('wave-start', () => this.sound.play('sfx-enemy-wave', { volume: 0.5 }));
|
this.events.on('wave-start', () => this.sound.play('sfx-enemy-wave', { volume: 0.5 }));
|
||||||
this.events.on('zone-waves-complete', () => this._startZoneExit());
|
this.events.on('zone-waves-complete', () => this._startZoneExit());
|
||||||
|
this.events.on('player-died', () => this._onPlayerDied());
|
||||||
|
this.events.on('player-respawned', () => { this.waveManager.enemiesFrozen = false; });
|
||||||
|
|
||||||
this.reticle = new Reticle(this);
|
this.reticle = new Reticle(this);
|
||||||
|
|
||||||
|
|
@ -269,6 +271,27 @@ export class GameScene extends Phaser.Scene {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onPlayerDied() {
|
||||||
|
const W = this.scale.width;
|
||||||
|
const H = this.scale.height;
|
||||||
|
const cx = W / 2;
|
||||||
|
const cy = H / 2;
|
||||||
|
|
||||||
|
// Destroy all enemy projectiles
|
||||||
|
this._enemyProjectiles.forEach(p => { if (p?.active) p.destroy(); });
|
||||||
|
this._enemyProjectiles = [];
|
||||||
|
|
||||||
|
// Destroy enemies within 150px of screen centre
|
||||||
|
this.waveManager.enemies.forEach(e => {
|
||||||
|
if (e.active && Phaser.Math.Distance.Between(e.x, e.y, cx, cy) < 150) {
|
||||||
|
e.takeDamage(99999);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Freeze remaining enemies for the duration of invincibility
|
||||||
|
this.waveManager.enemiesFrozen = true;
|
||||||
|
}
|
||||||
|
|
||||||
_checkBulletHits() {
|
_checkBulletHits() {
|
||||||
const bullets = this.player.bullets.getChildren();
|
const bullets = this.player.bullets.getChildren();
|
||||||
const enemies = this.waveManager.enemies;
|
const enemies = this.waveManager.enemies;
|
||||||
|
|
@ -490,7 +513,17 @@ export class GameScene extends Phaser.Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
shutdown() {
|
shutdown() {
|
||||||
this.events.removeAllListeners();
|
// Remove only our custom listeners — removeAllListeners() would also strip
|
||||||
|
// Phaser's internal scene lifecycle listeners and corrupt the next create().
|
||||||
|
this.events.off('enemy-killed');
|
||||||
|
this.events.off('enemy-projectile-spawned');
|
||||||
|
this.events.off('level-up');
|
||||||
|
this.events.off('game-over');
|
||||||
|
this.events.off('victory');
|
||||||
|
this.events.off('wave-start');
|
||||||
|
this.events.off('zone-waves-complete');
|
||||||
|
this.events.off('player-died');
|
||||||
|
this.events.off('player-respawned');
|
||||||
this._barrierColliders?.forEach(c => c.destroy());
|
this._barrierColliders?.forEach(c => c.destroy());
|
||||||
this.reticle?.destroy();
|
this.reticle?.destroy();
|
||||||
this.barrierManager?.destroy();
|
this.barrierManager?.destroy();
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ export class WaveManager {
|
||||||
this.waveIndex = 0;
|
this.waveIndex = 0;
|
||||||
this.enemies = [];
|
this.enemies = [];
|
||||||
this.active = false;
|
this.active = false;
|
||||||
|
this.enemiesFrozen = false;
|
||||||
this.spriteGroup = scene.physics.add.group();
|
this.spriteGroup = scene.physics.add.group();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -70,8 +71,12 @@ export class WaveManager {
|
||||||
// Prune dead enemies
|
// Prune dead enemies
|
||||||
this.enemies = this.enemies.filter(e => e.active);
|
this.enemies = this.enemies.filter(e => e.active);
|
||||||
|
|
||||||
// Update living enemies
|
// Update living enemies (skip when frozen after player death)
|
||||||
this.enemies.forEach(e => e.update(delta));
|
if (this.enemiesFrozen) {
|
||||||
|
this.enemies.forEach(e => { if (e.sprite?.body) e.sprite.body.setVelocity(0, 0); });
|
||||||
|
} else {
|
||||||
|
this.enemies.forEach(e => e.update(delta));
|
||||||
|
}
|
||||||
|
|
||||||
// Check wave clear
|
// Check wave clear
|
||||||
if (this.enemies.length === 0) {
|
if (this.enemies.length === 0) {
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,8 @@ export class HUD {
|
||||||
}
|
}
|
||||||
|
|
||||||
destroy() {
|
destroy() {
|
||||||
|
this.scene.events.off('wave-start');
|
||||||
|
this.scene.events.off('zone-clear');
|
||||||
[this._hpLabel, this._hpBg, this._hpFill, this._xpBg, this._xpFill, this._xpLabel, this._zoneText, ...this._lifeIcons]
|
[this._hpLabel, this._hpBg, this._hpFill, this._xpBg, this._xpFill, this._xpLabel, this._zoneText, ...this._lifeIcons]
|
||||||
.forEach(o => o?.destroy());
|
.forEach(o => o?.destroy());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue