149 lines
4.0 KiB
TypeScript
149 lines
4.0 KiB
TypeScript
import type Phaser from 'phaser'
|
||
import { MAP_COLS, MAP_ROWS, HUD_HEIGHT, GAME_HEIGHT, GAME_WIDTH } from './constants'
|
||
import { GameManager } from './GameManager'
|
||
import {
|
||
PATH_TILES,
|
||
getCellSize,
|
||
drawAllTiles,
|
||
renderMapLabels,
|
||
renderHUD,
|
||
updateKPIBar,
|
||
BAR_X,
|
||
BAR_Y,
|
||
BAR_W,
|
||
BAR_H,
|
||
} from './mapRenderer'
|
||
|
||
/**
|
||
* 创建主游戏场景类(工厂函数,接收动态导入的 Phaser 实例)
|
||
* 这样可以保证 SSR 安全(只在客户端执行)
|
||
*/
|
||
export function createGameScene(PhaserLib: typeof Phaser): typeof Phaser.Scene {
|
||
class GameScene extends PhaserLib.Scene {
|
||
private manager!: GameManager
|
||
private kpiBar!: Phaser.GameObjects.Graphics
|
||
private kpiText!: Phaser.GameObjects.Text
|
||
private hcText!: Phaser.GameObjects.Text
|
||
private hoveredTile: { col: number; row: number } | null = null
|
||
private tileGraphics!: Phaser.GameObjects.Graphics
|
||
|
||
constructor() {
|
||
super({ key: 'GameScene' })
|
||
}
|
||
|
||
create(): void {
|
||
this.manager = GameManager.getInstance()
|
||
this.manager.reset()
|
||
this.manager.gameState = 'playing'
|
||
|
||
// 渲染地图
|
||
this.tileGraphics = this.add.graphics()
|
||
drawAllTiles(this.tileGraphics, null)
|
||
|
||
// 地图装饰标签
|
||
renderMapLabels(this)
|
||
|
||
// HUD(在地图之上)
|
||
const hud = renderHUD(this)
|
||
this.kpiBar = hud.kpiBar
|
||
this.kpiText = hud.kpiText
|
||
this.hcText = hud.hcText
|
||
|
||
// 鼠标交互
|
||
this.setupInteraction()
|
||
|
||
// GameManager 事件回调 → 更新 HUD
|
||
this.manager.onKPIChange.push((kpi: number) => {
|
||
updateKPIBar(this.kpiBar, kpi)
|
||
this.kpiText.setText(`${kpi}%`)
|
||
})
|
||
this.manager.onHCChange.push((hc: number) => {
|
||
this.hcText.setText(`HC: ${hc}`)
|
||
})
|
||
}
|
||
|
||
/** 注册鼠标悬停 + 点击事件 */
|
||
private setupInteraction(): void {
|
||
const { cellW, cellH } = getCellSize()
|
||
|
||
this.input.on(
|
||
'pointermove',
|
||
(pointer: Phaser.Input.Pointer) => {
|
||
const col = Math.floor(pointer.x / cellW)
|
||
const row = Math.floor((pointer.y - HUD_HEIGHT) / cellH)
|
||
|
||
if (col >= 0 && col < MAP_COLS && row >= 0 && row < MAP_ROWS) {
|
||
if (!PATH_TILES.has(`${col},${row}`)) {
|
||
if (
|
||
!this.hoveredTile ||
|
||
this.hoveredTile.col !== col ||
|
||
this.hoveredTile.row !== row
|
||
) {
|
||
this.hoveredTile = { col, row }
|
||
drawAllTiles(this.tileGraphics, this.hoveredTile)
|
||
}
|
||
return
|
||
}
|
||
}
|
||
if (this.hoveredTile !== null) {
|
||
this.hoveredTile = null
|
||
drawAllTiles(this.tileGraphics, null)
|
||
}
|
||
}
|
||
)
|
||
|
||
this.input.on(
|
||
'pointerdown',
|
||
(pointer: Phaser.Input.Pointer) => {
|
||
const col = Math.floor(pointer.x / cellW)
|
||
const row = Math.floor((pointer.y - HUD_HEIGHT) / cellH)
|
||
|
||
if (
|
||
col >= 0 && col < MAP_COLS &&
|
||
row >= 0 && row < MAP_ROWS &&
|
||
!PATH_TILES.has(`${col},${row}`)
|
||
) {
|
||
this.showBuildPrompt(col, row, cellW, cellH)
|
||
}
|
||
}
|
||
)
|
||
}
|
||
|
||
/** 点击可建格子时的占位提示(Phase 1) */
|
||
private showBuildPrompt(
|
||
col: number,
|
||
row: number,
|
||
cellW: number,
|
||
cellH: number
|
||
): void {
|
||
const x = col * cellW + cellW / 2
|
||
const y = HUD_HEIGHT + row * cellH + cellH / 2
|
||
const tip = this.add
|
||
.text(x, y - 20, '建塔 (即将开放)', {
|
||
fontFamily: 'VT323, monospace',
|
||
fontSize: '18px',
|
||
color: '#F43F5E',
|
||
backgroundColor: '#0a1628',
|
||
padding: { x: 8, y: 4 },
|
||
})
|
||
.setOrigin(0.5, 1)
|
||
.setDepth(20)
|
||
|
||
this.time.delayedCall(1500, () => {
|
||
tip.destroy()
|
||
})
|
||
}
|
||
}
|
||
|
||
// 避免 unused variable 警告
|
||
void MAP_ROWS
|
||
void GAME_HEIGHT
|
||
void GAME_WIDTH
|
||
void BAR_X
|
||
void BAR_Y
|
||
void BAR_W
|
||
void BAR_H
|
||
|
||
return GameScene
|
||
}
|