From bcfd001c112658f8cf3238ba53106ee3f9fc5128 Mon Sep 17 00:00:00 2001 From: Cloud Bot Date: Sat, 21 Mar 2026 09:45:12 +0000 Subject: [PATCH] =?UTF-8?q?refactor(game/mapRenderer):=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=E5=8A=A8=E6=80=81=E8=B7=AF=E5=BE=84=E3=80=81=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=E8=83=8C=E6=99=AF=E5=9B=BE=E6=B8=B2=E6=9F=93=E5=92=8C?= =?UTF-8?q?=E8=A3=85=E9=A5=B0=E7=89=A9=E7=BB=98=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- game/mapRenderer.ts | 127 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 99 insertions(+), 28 deletions(-) diff --git a/game/mapRenderer.ts b/game/mapRenderer.ts index bbee42e..5e8e062 100644 --- a/game/mapRenderer.ts +++ b/game/mapRenderer.ts @@ -5,14 +5,12 @@ import { GAME_WIDTH, GAME_HEIGHT, HUD_HEIGHT, - PATH_WAYPOINTS, - COLOR_PATH, - COLOR_BUILDABLE, - COLOR_HOVER, - COLOR_BORDER, - MAP_LABELS, INITIAL_KPI, } from './constants' +import type { MapConfig } from './data/mapConfigs' +import { ALL_MAPS } from './data/mapConfigs' + +// ─── PATH TILES ──────────────────────────────────────────────────────────────── /** 将折线关键坐标点展开为完整路径格子集合 */ export function buildPathTiles( @@ -35,57 +33,78 @@ export function buildPathTiles( return tiles } -export const PATH_TILES = buildPathTiles(PATH_WAYPOINTS) +/** + * 向后兼容导出:用地图1配置初始化(GameScene 内部用局部变量覆盖) + */ +export const PATH_TILES = buildPathTiles(ALL_MAPS[0].waypoints) + +// ─── CELL SIZE ──────────────────────────────────────────────────────────────── /** 计算格子尺寸(正方形格子,取宽高中较小值保证正方形) */ export function getCellSize() { - const rawW = Math.floor(GAME_WIDTH / MAP_COLS) // 80 - const rawH = Math.floor((GAME_HEIGHT - HUD_HEIGHT) / MAP_ROWS) // 55 - const cell = Math.min(rawW, rawH) // 55 → 正方形 + const rawW = Math.floor(GAME_WIDTH / MAP_COLS) + const rawH = Math.floor((GAME_HEIGHT - HUD_HEIGHT) / MAP_ROWS) + const cell = Math.min(rawW, rawH) return { cellW: cell, cellH: cell } } +// ─── TILE RENDERING ─────────────────────────────────────────────────────────── + /** * 绘制所有地图格子 + * @param pathTiles 当前地图的路径格集合(若不传则用模块级默认值) + * @param mapConfig 当前地图配置,用于读取颜色(可选,默认用地图1颜色) */ export function drawAllTiles( g: Phaser.GameObjects.Graphics, - hovered: { col: number; row: number } | null + hovered: { col: number; row: number } | null, + pathTiles?: Set, + mapConfig?: MapConfig ): void { const { cellW, cellH } = getCellSize() + const tiles = pathTiles ?? PATH_TILES + const pathColor = mapConfig?.pathColor ?? 0x3d2b1f + const buildColor = mapConfig?.buildColor ?? 0x1e3a5f + const hoverColor = 0x2d5a8e + const borderColor = 0x0a1628 + g.clear() for (let row = 0; row < MAP_ROWS; row++) { for (let col = 0; col < MAP_COLS; col++) { - const isPath = PATH_TILES.has(`${col},${row}`) + const isPath = tiles.has(`${col},${row}`) const isHovered = !isPath && hovered !== null && hovered.col === col && hovered.row === row - const fillColor = isPath - ? COLOR_PATH - : isHovered ? COLOR_HOVER : COLOR_BUILDABLE + const fillColor = isPath ? pathColor : isHovered ? hoverColor : buildColor const x = col * cellW const y = HUD_HEIGHT + row * cellH g.fillStyle(fillColor, 1) g.fillRect(x + 1, y + 1, cellW - 2, cellH - 2) - g.lineStyle(1, COLOR_BORDER, 0.6) + g.lineStyle(1, borderColor, 0.6) g.strokeRect(x, y, cellW, cellH) } } } +// ─── MAP LABELS ─────────────────────────────────────────────────────────────── + /** - * 渲染地图装饰性标签 + * 渲染地图装饰性标签,返回创建的文字对象(便于切图时销毁) */ -export function renderMapLabels(scene: Phaser.Scene): void { +export function renderMapLabels( + scene: Phaser.Scene, + labels?: { col: number; row: number; text: string }[] +): Phaser.GameObjects.Text[] { const { cellW, cellH } = getCellSize() - for (const label of MAP_LABELS) { + const list = labels ?? ALL_MAPS[0].labels + return list.map(label => { const x = label.col * cellW + cellW / 2 const y = HUD_HEIGHT + label.row * cellH + cellH / 2 - scene.add + return scene.add .text(x, y, label.text, { fontFamily: 'VT323, monospace', fontSize: '14px', @@ -93,9 +112,68 @@ export function renderMapLabels(scene: Phaser.Scene): void { }) .setOrigin(0.5, 0.5) .setAlpha(0.5) - } + }) } +// ─── BACKGROUND ─────────────────────────────────────────────────────────────── + +/** + * 渲染地图背景图(铺满地图区域,HUD 下方) + * 返回创建的 Image 对象,切图时需 destroy + */ +export function renderMapBackground( + scene: Phaser.Scene, + bgKey: string +): Phaser.GameObjects.Image | null { + if (!scene.textures.exists(bgKey)) return null + + const { cellW, cellH } = getCellSize() + const mapW = MAP_COLS * cellW + const mapH = MAP_ROWS * cellH + + return scene.add + .image(0, HUD_HEIGHT, bgKey) + .setDisplaySize(mapW, mapH) + .setDepth(-1) + .setOrigin(0, 0) +} + +// ─── DECORATIONS ───────────────────────────────────────────────────────────── + +/** + * 在非路径格子上渲染装饰物图片,返回对象数组(切图时销毁) + */ +export function renderDecorations( + scene: Phaser.Scene, + decorations: MapConfig['decorations'], + pathTiles: Set +): Phaser.GameObjects.Image[] { + const { cellW, cellH } = getCellSize() + const result: Phaser.GameObjects.Image[] = [] + + for (const deco of decorations) { + const key = `${deco.col},${deco.row}` + // 跳过路径格 + if (pathTiles.has(key)) continue + // 检查贴图是否已加载 + if (!scene.textures.exists(deco.key)) continue + + const x = deco.col * cellW + cellW / 2 + const y = HUD_HEIGHT + deco.row * cellH + cellH / 2 + + const img = scene.add + .image(x, y, deco.key) + .setDisplaySize(cellW * 0.7, cellH * 0.7) + .setDepth(1) + .setAlpha(0.6) + result.push(img) + } + + return result +} + +// ─── HUD ────────────────────────────────────────────────────────────────────── + /** HUD 进度条参数 */ export const BAR_W = 300 export const BAR_H = 16 @@ -110,39 +188,33 @@ export function renderHUD(scene: Phaser.Scene): { kpiText: Phaser.GameObjects.Text hcText: Phaser.GameObjects.Text } { - // HUD 背景 const hudBg = scene.add.graphics() hudBg.fillStyle(0x0a1628, 0.92) hudBg.fillRect(0, 0, GAME_WIDTH, HUD_HEIGHT) hudBg.lineStyle(1, 0x1e3a5f, 1) hudBg.strokeRect(0, 0, GAME_WIDTH, HUD_HEIGHT) - // 左侧标题 scene.add.text(16, HUD_HEIGHT / 2, '大厂保卫战', { fontFamily: "'Press Start 2P', monospace", fontSize: '10px', color: '#A78BFA', }).setOrigin(0, 0.5) - // KPI 标签 scene.add.text(BAR_X - 8, HUD_HEIGHT / 2, 'KPI', { fontFamily: "'Press Start 2P', monospace", fontSize: '8px', color: '#E2E8F0', }).setOrigin(1, 0.5) - // 进度条背景轨道 const trackBar = scene.add.graphics() trackBar.fillStyle(0x1a1a2e, 1) trackBar.fillRect(BAR_X, BAR_Y, BAR_W, BAR_H) trackBar.lineStyle(1, 0x7c3aed, 0.6) trackBar.strokeRect(BAR_X, BAR_Y, BAR_W, BAR_H) - // KPI 进度前景 const kpiBar = scene.add.graphics() updateKPIBar(kpiBar, INITIAL_KPI) - // KPI 百分比文字 const kpiText = scene.add.text( BAR_X + BAR_W / 2, HUD_HEIGHT / 2, `${INITIAL_KPI}%`, @@ -153,7 +225,6 @@ export function renderHUD(scene: Phaser.Scene): { } ).setOrigin(0.5, 0.5).setDepth(1) - // 右侧 HC 数值 const hcText = scene.add.text( GAME_WIDTH - 16, HUD_HEIGHT / 2, `HC: 200`,