7.1 KiB
7.1 KiB
Task 1A+1B: 游戏基础框架搭建
任务概要
在现有 Next.js 项目中,安装 Phaser.js,改造主页(封面),创建游戏页面,实现 Phaser 游戏框架挂载 + S型地图渲染。
执行步骤
Step 1: 安装 Phaser.js
pnpm add phaser
Step 2: 改造 app/page.tsx(主页/游戏封面)
完全重写主页,展示游戏封面。注意:必须覆盖模板原有 UI,不保留任何模板样式。
设计要求(参考 design-system/大厂保卫战/MASTER.md):
- 背景色:
#0F0F23(深夜宇宙蓝) - 标题字体:Press Start 2P(像素字体),颜色
#A78BFA(霓虹紫) - 副标题:VT323 字体
- 主色 CTA 按钮(进入游戏):
#F43F5E红色 - 效果:CRT 扫描线叠加层(
::before伪元素,repeating-linear-gradient 细黑线) - 霓虹发光效果:标题
text-shadow双层发光 - 装饰性文字:背景中随机排列大厂黑话(低透明度)
主页内容结构:
[全屏黑色背景]
[CRT扫描线叠加层]
[装饰黑话背景文字]
[中央卡片]
标题:大厂保卫战
副标题:最后的打工人
英文副标:THE LAST GRINDER
描述:保住KPI,战胜空降VP
[开始游戏] 按钮 → 跳转 /game
[底部版权:像素风格]
Step 3: 创建 app/game/page.tsx(游戏页面)
'use client'
import { useEffect, useRef } from 'react'
export default function GamePage() {
const gameRef = useRef<any>(null)
useEffect(() => {
let game: any = null
const initGame = async () => {
const Phaser = (await import('phaser')).default
const { createGameConfig } = await import('@/game/config')
if (gameRef.current && !game) {
game = new Phaser.Game(createGameConfig('game-container'))
}
}
initGame()
return () => {
game?.destroy(true)
}
}, [])
return (
<div className="w-full h-screen bg-[#0F0F23] overflow-hidden">
<div id="game-container" className="w-full h-full" />
</div>
)
}
Step 4: 创建游戏核心文件
game/constants.ts(游戏常量):
export const MAP_COLS = 16
export const MAP_ROWS = 12
export const TILE_SIZE = 80 // 每格80px,总计 1280x960,Phaser会缩放
export const GAME_WIDTH = 1280
export const GAME_HEIGHT = 720
// S型路径格子坐标
export const PATH_WAYPOINTS = [
{ x: 0, y: 2 },
{ x: 11, y: 2 },
{ x: 11, y: 9 },
{ x: 15, y: 9 },
]
// 游戏初始数值
export const INITIAL_HC = 200
export const INITIAL_KPI = 100
export const STAMINA_MAX = 100
export const STAMINA_REGEN = 5 // 每秒恢复量
export const COFFEE_COST = 10 // 瑞幸咖啡 HC 成本
// 颜色常量
export const COLOR_PATH = 0x3d2b1f
export const COLOR_BUILDABLE = 0x1e3a5f
export const COLOR_HOVER = 0x2d5a8e
export const COLOR_BORDER = 0x0a1628
game/config.ts(Phaser 配置):
import Phaser from 'phaser'
import { GAME_WIDTH, GAME_HEIGHT } from './constants'
export function createGameConfig(containerId: string): Phaser.Types.Core.GameConfig {
return {
type: Phaser.AUTO,
width: GAME_WIDTH,
height: GAME_HEIGHT,
parent: containerId,
backgroundColor: '#0a1628',
scale: {
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_BOTH,
},
scene: [], // 在 GameScene 中动态加载
physics: {
default: 'arcade',
arcade: { debug: false }
}
}
}
game/GameScene.ts(主游戏场景):
核心地图渲染逻辑:
- 创建 16x12 格子网格
- 根据 PATH_WAYPOINTS 计算路径格子集合(路径上的每个格子都是路径格)
- 路径格子:深褐色(
0x3d2b1f) - 可建塔格子:深蓝色(
0x1e3a5f) - 格子间有1px间距
- 鼠标悬停非路径格子时高亮
- 点击非路径格子:触发建塔逻辑(Phase 1先只做UI提示)
- 添加地图装饰性文字("面试间"、"财务室")
- 场景中显示:顶部 HUD 区域(KPI进度条 + HC数值)
地图路径计算方式(不能只用 4 个坐标点,需要填充中间格子):
// 将折线坐标展开为完整路径格子集合
function buildPathTiles(waypoints): Set<string> {
const tiles = new Set<string>()
for (let i = 0; i < waypoints.length - 1; i++) {
const from = waypoints[i]
const to = waypoints[i + 1]
// 水平或垂直连线
if (from.x === to.x) {
for (let y = Math.min(from.y, to.y); y <= Math.max(from.y, to.y); y++) {
tiles.add(`${from.x},${y}`)
}
} else {
for (let x = Math.min(from.x, to.x); x <= Math.max(from.x, to.x); x++) {
tiles.add(`${x},${from.y}`)
}
}
}
return tiles
}
HUD 设计(Phaser Text/Graphics 实现,而非 HTML 层):
- 顶部黑色半透明条(全宽,高度60px)
- 左:游戏标题 "大厂保卫战" (Press Start 2P,小字号)
- 中:KPI 进度条(宽300px,绿→黄→红渐变)
- 右:HC 数值 "HC: 200"
game/GameManager.ts(游戏状态管理器):
export class GameManager {
private static instance: GameManager
public hc: number = INITIAL_HC
public kpi: number = INITIAL_KPI
public currentWave: number = 0
public gameState: 'idle' | 'playing' | 'paused' | 'victory' | 'defeat' = 'idle'
static getInstance(): GameManager { ... }
spendHC(amount: number): boolean { ... } // 扣除HC,不足返回false
addHC(amount: number): void { ... }
reduceKPI(amount: number): void { ... } // 减少KPI,归零触发失败
// 事件系统(用于 Scene 与 UI 通信)
onHCChange: ((hc: number) => void)[] = []
onKPIChange: ((kpi: number) => void)[] = []
onGameOver: (() => void)[] = []
onVictory: (() => void)[] = []
}
Step 5: 更新 app/layout.tsx
在 layout 中引入 Google Fonts(Press Start 2P + VT323):
// 在 <head> 中添加
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossOrigin="anonymous" />
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323:wght@400&display=swap" rel="stylesheet" />
Step 6: 更新 app/globals.css
添加游戏全局样式:
- CSS 变量(颜色 token)
- CRT 扫描线效果(供主页使用)
- 霓虹发光 keyframes 动画
- 像素字体 class
验收标准
pnpm dev启动成功,无编译错误- 访问
/:显示游戏封面,有进入游戏按钮,霓虹效果正常 - 点击进入游戏跳转至
/game - 访问
/game:渲染 16x12 格子地图,S型路径可见(深褐色路径,深蓝色可建区域) - 鼠标悬停可建塔格子时高亮
- 顶部 HUD 显示 KPI 进度条和 HC 数值
相关上下文
- 设计系统:
design-system/大厂保卫战/MASTER.md - PRD:
.docs/prd-tower-defense-game.md - 计划文档:
.docs/plans/2026-03-21-tower-defense-game.md - 开发规范:
@rules/dev-best-practices.md(必须先阅读)
完成开发后,按 @rules/atomic-commit.md 规范,将变更按逻辑模块分组提交(禁止 git add .),确保所有文件均已 commit 后再结束任务。