feat(game): 创建游戏核心框架(常量、配置、状态管理、地图渲染、主场景)

This commit is contained in:
Cloud Bot
2026-03-21 07:56:48 +00:00
parent 80024a5200
commit 85377f1cb2
5 changed files with 489 additions and 0 deletions

148
game/GameScene.ts Normal file
View File

@@ -0,0 +1,148 @@
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
}