refactor(game/enemies/WaveManager): 接受外部波次配置和难度倍率,支持多地图切换
This commit is contained in:
@@ -4,96 +4,65 @@ import { FreshGraduate } from './FreshGraduate'
|
|||||||
import { OldEmployee } from './OldEmployee'
|
import { OldEmployee } from './OldEmployee'
|
||||||
import { TroubleMaker } from './TroubleMaker'
|
import { TroubleMaker } from './TroubleMaker'
|
||||||
import { BossVP } from './BossVP'
|
import { BossVP } from './BossVP'
|
||||||
|
import type { WaveConfigEntry, DifficultyLevel } from '../data/mapConfigs'
|
||||||
|
import { DIFFICULTY_MULTIPLIER } from '../data/mapConfigs'
|
||||||
|
|
||||||
interface EnemyGroup {
|
type EnemyType = 'FreshGraduate' | 'OldEmployee' | 'TroubleMaker' | 'BossVP'
|
||||||
type: 'FreshGraduate' | 'OldEmployee' | 'TroubleMaker' | 'BossVP'
|
|
||||||
count: number
|
interface WaveCallbacks {
|
||||||
interval: number
|
onWaveComplete: () => void
|
||||||
|
onAllWavesComplete: () => void
|
||||||
|
onDestroyRandomTower: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
interface WaveConfig {
|
|
||||||
enemies: EnemyGroup[]
|
|
||||||
}
|
|
||||||
|
|
||||||
const WAVE_CONFIG: WaveConfig[] = [
|
|
||||||
{ enemies: [{ type: 'FreshGraduate', count: 10, interval: 800 }] },
|
|
||||||
{
|
|
||||||
enemies: [
|
|
||||||
{ type: 'FreshGraduate', count: 8, interval: 800 },
|
|
||||||
{ type: 'OldEmployee', count: 3, interval: 2000 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enemies: [
|
|
||||||
{ type: 'OldEmployee', count: 5, interval: 2000 },
|
|
||||||
{ type: 'TroubleMaker', count: 3, interval: 1500 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enemies: [
|
|
||||||
{ type: 'FreshGraduate', count: 12, interval: 600 },
|
|
||||||
{ type: 'TroubleMaker', count: 2, interval: 1500 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enemies: [
|
|
||||||
{ type: 'OldEmployee', count: 6, interval: 1500 },
|
|
||||||
{ type: 'TroubleMaker', count: 3, interval: 1500 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
enemies: [
|
|
||||||
{ type: 'BossVP', count: 1, interval: 0 },
|
|
||||||
{ type: 'OldEmployee', count: 4, interval: 2000 },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
export class WaveManager {
|
export class WaveManager {
|
||||||
private scene: Phaser.Scene
|
private scene: Phaser.Scene
|
||||||
private activeEnemies: EnemyBase[] = []
|
private activeEnemies: EnemyBase[] = []
|
||||||
private pathPoints: PathPoint[]
|
private pathPoints: PathPoint[]
|
||||||
private currentWave: number = 0
|
private currentWave: number = 0
|
||||||
private isSpawning: boolean = false
|
private isSpawning: boolean = false
|
||||||
private onWave3Complete?: () => void
|
private waveConfigs: WaveConfigEntry[]
|
||||||
private onAllWavesComplete?: () => void
|
private difficulty: DifficultyLevel
|
||||||
private onDestroyRandomTower?: () => void
|
private callbacks: WaveCallbacks
|
||||||
private wave3Completed: boolean = false
|
private waveCompleteFired: boolean = false
|
||||||
|
private allCompleteGuard: boolean = false
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: Phaser.Scene,
|
scene: Phaser.Scene,
|
||||||
onWave3Complete?: () => void,
|
waveConfigs: WaveConfigEntry[],
|
||||||
onAllWavesComplete?: () => void,
|
difficulty: DifficultyLevel,
|
||||||
onDestroyRandomTower?: () => void
|
callbacks: WaveCallbacks,
|
||||||
|
waypoints?: readonly { x: number; y: number }[]
|
||||||
) {
|
) {
|
||||||
this.scene = scene
|
this.scene = scene
|
||||||
this.pathPoints = buildFullPath()
|
this.waveConfigs = waveConfigs
|
||||||
this.onWave3Complete = onWave3Complete
|
this.difficulty = difficulty
|
||||||
this.onAllWavesComplete = onAllWavesComplete
|
this.callbacks = callbacks
|
||||||
this.onDestroyRandomTower = onDestroyRandomTower
|
this.pathPoints = buildFullPath(waypoints)
|
||||||
}
|
}
|
||||||
|
|
||||||
get totalWaves(): number {
|
get totalWaves(): number {
|
||||||
return WAVE_CONFIG.length
|
return this.waveConfigs.length
|
||||||
}
|
}
|
||||||
|
|
||||||
startNextWave(): void {
|
startNextWave(): void {
|
||||||
if (this.isSpawning || this.currentWave >= WAVE_CONFIG.length) return
|
if (this.isSpawning || this.currentWave >= this.waveConfigs.length) return
|
||||||
const config = WAVE_CONFIG[this.currentWave]
|
const config = this.waveConfigs[this.currentWave]
|
||||||
this.currentWave++
|
this.currentWave++
|
||||||
this.isSpawning = true
|
this.isSpawning = true
|
||||||
this.spawnWave(config)
|
this.spawnWave(config)
|
||||||
}
|
}
|
||||||
|
|
||||||
private spawnWave(config: WaveConfig): void {
|
private spawnWave(config: WaveConfigEntry): void {
|
||||||
// 将所有怪物组展开为按时间排列的生成序列
|
const multiplier = DIFFICULTY_MULTIPLIER[this.difficulty]
|
||||||
const spawnQueue: { type: EnemyGroup['type']; delay: number }[] = []
|
const spawnQueue: { type: EnemyType; delay: number }[] = []
|
||||||
|
|
||||||
for (const group of config.enemies) {
|
for (const group of config.enemies) {
|
||||||
for (let i = 0; i < group.count; i++) {
|
const count = Math.ceil(group.count * multiplier.enemyCount)
|
||||||
|
for (let i = 0; i < count; i++) {
|
||||||
spawnQueue.push({ type: group.type, delay: group.interval * i })
|
spawnQueue.push({ type: group.type, delay: group.interval * i })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 按 delay 升序排列,同时生成
|
|
||||||
spawnQueue.sort((a, b) => a.delay - b.delay)
|
spawnQueue.sort((a, b) => a.delay - b.delay)
|
||||||
|
|
||||||
let completed = 0
|
let completed = 0
|
||||||
@@ -110,25 +79,28 @@ export class WaveManager {
|
|||||||
if (spawnQueue.length === 0) this.isSpawning = false
|
if (spawnQueue.length === 0) this.isSpawning = false
|
||||||
}
|
}
|
||||||
|
|
||||||
private spawnEnemy(type: EnemyGroup['type']): EnemyBase {
|
private spawnEnemy(type: EnemyType): EnemyBase {
|
||||||
let enemy: EnemyBase
|
const multiplier = DIFFICULTY_MULTIPLIER[this.difficulty]
|
||||||
const pts = [...this.pathPoints]
|
const pts = [...this.pathPoints]
|
||||||
|
let enemy: EnemyBase
|
||||||
|
|
||||||
|
const speedMult = multiplier.enemySpeed
|
||||||
|
const hpMult = type === 'BossVP' ? multiplier.bossHp : 1.0
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'OldEmployee':
|
case 'OldEmployee':
|
||||||
enemy = new OldEmployee(this.scene, pts)
|
enemy = new OldEmployee(this.scene, pts, speedMult, hpMult)
|
||||||
break
|
break
|
||||||
case 'TroubleMaker':
|
case 'TroubleMaker':
|
||||||
enemy = new TroubleMaker(this.scene, pts)
|
enemy = new TroubleMaker(this.scene, pts, speedMult, hpMult)
|
||||||
break
|
break
|
||||||
case 'BossVP':
|
case 'BossVP':
|
||||||
enemy = new BossVP(this.scene, pts, this.onDestroyRandomTower)
|
enemy = new BossVP(this.scene, pts, this.callbacks.onDestroyRandomTower, speedMult, hpMult)
|
||||||
break
|
break
|
||||||
default:
|
default:
|
||||||
enemy = new FreshGraduate(this.scene, pts)
|
enemy = new FreshGraduate(this.scene, pts, speedMult, hpMult)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 随机显示语录
|
|
||||||
this.scene.time.delayedCall(1000 + Math.random() * 2000, () => {
|
this.scene.time.delayedCall(1000 + Math.random() * 2000, () => {
|
||||||
if (!enemy.isDead) enemy.showQuote()
|
if (!enemy.isDead) enemy.showQuote()
|
||||||
})
|
})
|
||||||
@@ -147,24 +119,26 @@ export class WaveManager {
|
|||||||
e.update(delta)
|
e.update(delta)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查第3波完成后触发周报
|
// 中途波次完成回调(用于触发周报等)
|
||||||
if (
|
if (
|
||||||
this.currentWave === 3 &&
|
this.currentWave === 3 &&
|
||||||
!this.isSpawning &&
|
!this.isSpawning &&
|
||||||
this.activeEnemies.length === 0 &&
|
this.activeEnemies.length === 0 &&
|
||||||
!this.wave3Completed
|
!this.waveCompleteFired
|
||||||
) {
|
) {
|
||||||
this.wave3Completed = true
|
this.waveCompleteFired = true
|
||||||
this.onWave3Complete?.()
|
this.callbacks.onWaveComplete()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查全部波次完成
|
// 全部波次完成
|
||||||
if (
|
if (
|
||||||
this.currentWave >= WAVE_CONFIG.length &&
|
this.currentWave >= this.waveConfigs.length &&
|
||||||
!this.isSpawning &&
|
!this.isSpawning &&
|
||||||
this.activeEnemies.length === 0
|
this.activeEnemies.length === 0 &&
|
||||||
|
!this.allCompleteGuard
|
||||||
) {
|
) {
|
||||||
this.onAllWavesComplete?.()
|
this.allCompleteGuard = true
|
||||||
|
this.callbacks.onAllWavesComplete()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,10 +147,18 @@ export class WaveManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hasMoreWaves(): boolean {
|
hasMoreWaves(): boolean {
|
||||||
return this.currentWave < WAVE_CONFIG.length
|
return this.currentWave < this.waveConfigs.length
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentWaveNumber(): number {
|
getCurrentWaveNumber(): number {
|
||||||
return this.currentWave
|
return this.currentWave
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 清除所有活跃怪物(切图时调用) */
|
||||||
|
clearAllEnemies(): void {
|
||||||
|
for (const e of this.activeEnemies) {
|
||||||
|
if (!e.isDead) e.destroy()
|
||||||
|
}
|
||||||
|
this.activeEnemies = []
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user