111 lines
2.9 KiB
JavaScript
111 lines
2.9 KiB
JavaScript
import { ChaseEnemy } from '../entities/enemies/ChaseEnemy.js';
|
|
import { ShooterEnemy } from '../entities/enemies/ShooterEnemy.js';
|
|
import { SwarmerEnemy } from '../entities/enemies/SwarmerEnemy.js';
|
|
|
|
const ENEMY_CLASSES = { ChaseEnemy, ShooterEnemy, SwarmerEnemy };
|
|
const SPAWN_MARGIN = 40;
|
|
|
|
export class WaveManager {
|
|
constructor(scene, player) {
|
|
this.scene = scene;
|
|
this.player = player;
|
|
this.zones = [];
|
|
this.zoneIndex = 0;
|
|
this.waveIndex = 0;
|
|
this.enemies = [];
|
|
this.active = false;
|
|
}
|
|
|
|
load(data) {
|
|
this.zones = data;
|
|
}
|
|
|
|
start() {
|
|
this.active = true;
|
|
this._spawnWave();
|
|
}
|
|
|
|
get currentZone() { return this.zones[this.zoneIndex]; }
|
|
get currentWave() { return this.currentZone?.waves[this.waveIndex]; }
|
|
get zoneNum() { return this.zoneIndex + 1; }
|
|
get waveNum() { return this.waveIndex + 1; }
|
|
get totalWaves() { return this.currentZone?.waves.length ?? 0; }
|
|
|
|
_spawnWave() {
|
|
const wave = this.currentWave;
|
|
if (!wave) return;
|
|
|
|
this.scene.events.emit('wave-start', { zone: this.zoneNum, wave: this.waveNum, totalWaves: this.totalWaves });
|
|
|
|
wave.enemies.forEach(({ type, count }) => {
|
|
const EnemyClass = ENEMY_CLASSES[type];
|
|
if (!EnemyClass) return;
|
|
for (let i = 0; i < count; i++) {
|
|
const [x, y] = this._edgePosition();
|
|
const enemy = new EnemyClass(this.scene, x, y, this.player);
|
|
this.enemies.push(enemy);
|
|
}
|
|
});
|
|
}
|
|
|
|
_edgePosition() {
|
|
const W = this.scene.scale.width;
|
|
const H = this.scene.scale.height;
|
|
const side = Phaser.Math.Between(0, 3);
|
|
switch (side) {
|
|
case 0: return [Phaser.Math.Between(0, W), -SPAWN_MARGIN];
|
|
case 1: return [W + SPAWN_MARGIN, Phaser.Math.Between(0, H)];
|
|
case 2: return [Phaser.Math.Between(0, W), H + SPAWN_MARGIN];
|
|
case 3: return [-SPAWN_MARGIN, Phaser.Math.Between(0, H)];
|
|
}
|
|
}
|
|
|
|
update(delta) {
|
|
if (!this.active) return;
|
|
|
|
// Prune dead enemies
|
|
this.enemies = this.enemies.filter(e => e.active);
|
|
|
|
// Update living enemies
|
|
this.enemies.forEach(e => e.update(delta));
|
|
|
|
// Check wave clear
|
|
if (this.enemies.length === 0) {
|
|
this.active = false;
|
|
this.scene.time.delayedCall(1500, () => this._advance());
|
|
}
|
|
}
|
|
|
|
_advance() {
|
|
this.waveIndex++;
|
|
|
|
if (this.waveIndex >= this.currentZone.waves.length) {
|
|
// Zone complete
|
|
this.waveIndex = 0;
|
|
this.zoneIndex++;
|
|
|
|
if (this.zoneIndex >= this.zones.length) {
|
|
this.scene.events.emit('victory');
|
|
return;
|
|
}
|
|
|
|
this.scene.events.emit('zone-clear', { zone: this.zoneNum });
|
|
this.scene.time.delayedCall(2500, () => {
|
|
this.active = true;
|
|
this._spawnWave();
|
|
});
|
|
} else {
|
|
this.active = true;
|
|
this._spawnWave();
|
|
}
|
|
}
|
|
|
|
reset() {
|
|
this.enemies.forEach(e => { if (e.active) e.destroy(); });
|
|
this.enemies = [];
|
|
this.zoneIndex = 0;
|
|
this.waveIndex = 0;
|
|
this.active = false;
|
|
}
|
|
}
|