docs: 添加PRD需求文档、任务计划和设计系统
This commit is contained in:
226
.docs/tasks/task-1ab-game-foundation.md
Normal file
226
.docs/tasks/task-1ab-game-foundation.md
Normal file
@@ -0,0 +1,226 @@
|
||||
# Task 1A+1B: 游戏基础框架搭建
|
||||
|
||||
## 任务概要
|
||||
在现有 Next.js 项目中,安装 Phaser.js,改造主页(封面),创建游戏页面,实现 Phaser 游戏框架挂载 + S型地图渲染。
|
||||
|
||||
## 执行步骤
|
||||
|
||||
### Step 1: 安装 Phaser.js
|
||||
```bash
|
||||
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`(游戏页面)
|
||||
```typescript
|
||||
'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`**(游戏常量):
|
||||
```typescript
|
||||
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 配置):
|
||||
```typescript
|
||||
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 个坐标点,需要填充中间格子):
|
||||
```typescript
|
||||
// 将折线坐标展开为完整路径格子集合
|
||||
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`**(游戏状态管理器):
|
||||
```typescript
|
||||
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):
|
||||
```tsx
|
||||
// 在 <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
|
||||
|
||||
## 验收标准
|
||||
1. `pnpm dev` 启动成功,无编译错误
|
||||
2. 访问 `/`:显示游戏封面,有进入游戏按钮,霓虹效果正常
|
||||
3. 点击进入游戏跳转至 `/game`
|
||||
4. 访问 `/game`:渲染 16x12 格子地图,S型路径可见(深褐色路径,深蓝色可建区域)
|
||||
5. 鼠标悬停可建塔格子时高亮
|
||||
6. 顶部 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 后再结束任务。
|
||||
Reference in New Issue
Block a user