Files
test1/game/GameManager.ts

129 lines
3.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import {
INITIAL_HC,
INITIAL_KPI,
} from './constants'
import type { DifficultyLevel } from './data/mapConfigs'
type GameState = 'idle' | 'playing' | 'paused' | 'victory' | 'defeat'
/**
* 游戏状态管理器(单例)
* 负责管理 HC人才储备、KPI、波次状态并通过回调事件通知 Scene
*/
export class GameManager {
private static instance: GameManager
public hc: number = INITIAL_HC
public kpi: number = INITIAL_KPI
public currentWave: number = 0
public gameState: GameState = 'idle'
// 难度与地图状态
public difficulty: DifficultyLevel = 'normal'
public currentMapIndex: number = 0 // 0=地图1, 1=地图2, 2=地图3
public totalWaveCleared: number = 0 // 总计已清理波次
// 事件回调Scene 通过这些 hook 更新 HUD
public onHCChange: ((hc: number) => void)[] = []
public onKPIChange: ((kpi: number) => void)[] = []
public onGameOver: (() => void)[] = []
public onVictory: (() => void)[] = []
private constructor() {}
static getInstance(): GameManager {
if (!GameManager.instance) {
GameManager.instance = new GameManager()
}
return GameManager.instance
}
/** 设置难度 */
setDifficulty(d: DifficultyLevel): void {
this.difficulty = d
}
/** 重置游戏状态(保留难度,重置其他字段) */
reset(): void {
this.hc = INITIAL_HC
this.kpi = INITIAL_KPI
this.currentWave = 0
this.gameState = 'idle'
this.currentMapIndex = 0
this.totalWaveCleared = 0
this.onHCChange = []
this.onKPIChange = []
this.onGameOver = []
this.onVictory = []
// difficulty 保留,不重置
}
/** 重置 HC 到初始值(进入下一关时调用,不带入上一关的余量) */
resetHC(): void {
this.hc = INITIAL_HC
this.onHCChange.forEach(cb => cb(this.hc))
}
/**
* 扣除 HC余额不足时返回 false
*/
spendHC(amount: number): boolean {
if (this.hc < amount) return false
this.hc -= amount
this.onHCChange.forEach(cb => cb(this.hc))
return true
}
/**
* 增加 HC
*/
addHC(amount: number): void {
this.hc += amount
this.onHCChange.forEach(cb => cb(this.hc))
}
/**
* 减少 KPI归零时触发 GameOver
*/
reduceKPI(amount: number): void {
this.kpi = Math.max(0, this.kpi - amount)
this.onKPIChange.forEach(cb => cb(this.kpi))
if (this.kpi <= 0 && this.gameState === 'playing') {
this.gameState = 'defeat'
this.onGameOver.forEach(cb => cb())
}
}
/**
* 增加 KPI不超过 100
*/
addKPI(amount: number): void {
this.kpi = Math.min(100, this.kpi + amount)
this.onKPIChange.forEach(cb => cb(this.kpi))
}
/** 暂停游戏(仅 playing 状态下有效) */
pause(): boolean {
if (this.gameState !== 'playing') return false
this.gameState = 'paused'
return true
}
/** 恢复游戏(仅 paused 状态下有效) */
resume(): boolean {
if (this.gameState !== 'paused') return false
this.gameState = 'playing'
return true
}
get isPaused(): boolean { return this.gameState === 'paused' }
/** 触发胜利 */
triggerVictory(): void {
if (this.gameState === 'playing') {
this.gameState = 'victory'
this.onVictory.forEach(cb => cb())
}
}
}