docs: 添加PRD需求文档、任务计划和设计系统

This commit is contained in:
Cloud Bot
2026-03-21 08:16:51 +00:00
parent 3a236fd294
commit 21e3da573e
6 changed files with 1608 additions and 0 deletions

View File

@@ -0,0 +1,239 @@
# 《大厂保卫战:最后的打工人》- 任务计划 v1.0
**日期:** 2026-03-21
**目标:** 在 Next.js 项目中,用 Phaser.js 实现完整的第一关塔防游戏
**设计文档:** `design-system/大厂保卫战/MASTER.md`
**需求文档:** `.docs/prd-tower-defense-game.md`
---
## 功能优先级
| 优先级 | 功能 | 说明 |
|--------|------|------|
| P0 | 游戏基础框架 + 主页入口 | Next.js 页面 + Phaser.js 集成 + 地图渲染 |
| P0 | 防御塔系统 | 4种塔的部署、攻击、精力管理 |
| P0 | 怪物波次系统 | 6波怪物 + 路径寻路 + 战斗逻辑 |
| P1 | 周报结算系统 | 第3波后触发的黑话问答弹窗 |
| P1 | 特殊技能与摸鱼机制 | 各塔特殊能力 + 精力恢复 + 咖啡购买 |
| P1 | 胜利/失败结算界面 | 钉钉风格弹窗 + 绩效评级 |
| P2 | 怪物头顶语录飘字 | 100条黑话随机飘过 |
---
## Phase 1当前批游戏基础框架 + 主页
**目标:** 搭建可运行的 Next.js + Phaser.js 框架,渲染 S 型地图,部署基础塔,实现预设路径怪物移动
### 任务列表
- [ ] **Task 1A: 安装依赖 + 创建游戏入口页面**
- 批次:当前批
- 执行方式:串行(基础设施)
- 前置依赖:无
- 目标:
- 安装 `phaser` npm 包
- 创建 `app/game/page.tsx`Next.js 游戏页面(`use client`
- 创建 `app/page.tsx`:主页(游戏封面 + 进入游戏按钮,覆盖模板原有页面)
- 字体:从 Google Fonts 加载 Press Start 2P + VT323
- 涉及范围:
- `package.json`(添加 phaser 依赖)
- `app/page.tsx`(主页重写)
- `app/game/page.tsx`(游戏页面新建)
- `app/layout.tsx`(添加字体 import
- `app/globals.css`(游戏全局样式)
- 验收标准:访问 `/game` 页面不报错,主页显示游戏封面
- 验证方式:`curl -s http://localhost:13000/game | grep -c "html"`
- [ ] **Task 1B: Phaser.js 游戏核心框架**
- 批次:当前批
- 执行方式:串行(依赖 1A
- 前置依赖Task 1A 完成
- 目标:
- 创建 `game/` 目录(游戏源码目录,非 Next.js app 目录)
- 实现 `game/GameScene.ts`主游戏场景S型地图渲染16x12格格子48px
- 实现 `game/config.ts`Phaser 配置Canvas 1280x720transparent background
- 实现 `game/constants.ts`游戏常量地图路径坐标、HC初始值200、KPI初始100等
- 实现 `game/GameManager.ts`游戏状态管理HC、KPI、波次、游戏状态
-`app/game/page.tsx` 中挂载 Phaser Game 实例useEffect
- 涉及范围:
- `game/config.ts`
- `game/constants.ts`
- `game/GameScene.ts`
- `game/GameManager.ts`
- `app/game/page.tsx`
- 关键实现细节:
- S型路径坐标`[(0,2),(7,2),(7,9),(15,9)]`,格子大小 48px
- 地图背景:深色办公室风格(`#0A1628`),路径用深褐色(`#2D1B00`
- 可建塔区域路径以外的格子点击触发建塔UI
- 所有 Phaser 相关代码只在客户端运行SSR 需跳过)
- 验收标准浏览器显示游戏地图S型路径可见格子可点击
- 验证方式:启动开发服务器后访问 `/game`
- [ ] **Task 1C: 防御塔基础系统(部署+攻击+精力)**
- 批次:当前批
- 执行方式:串行(依赖 1B
- 前置依赖Task 1B 完成
- 目标:
- 实现 `game/towers/TowerBase.ts`:塔基类(位置、成本、攻速、精力、攻击范围)
- 实现 4 种塔:
- `game/towers/InternTower.ts`00后实习生50HC近战
- `game/towers/SeniorDevTower.ts`P6资深开发120HC远程直线
- `game/towers/PPTMasterTower.ts`PPT大师100HC范围减速
- `game/towers/HRBPTower.ts`HRBP80HC辅助Buff
- 实现 `game/towers/TowerManager.ts`:塔的部署管理、攻击目标选择
- HUD 底部塔选择栏4个卡片显示名称、成本、当前可选状态
- 点击地图格子后弹出确认浮层,扣除 HC 后放置塔
- 塔的精力条显示(进度条悬浮在塔上方)
- 涉及范围:
- `game/towers/` 目录5个文件
- `game/GameScene.ts`(集成塔管理器)
- `game/ui/TowerPanel.ts`(底部塔选择 HUD
- 验收标准:可以点击格子选塔,扣除 HC 后塔出现在地图上,塔有精力条
- 验证方式:手动游玩验证
- [ ] **Task 1D: 怪物波次系统(路径寻路+战斗)**
- 批次:当前批
- 执行方式:串行(依赖 1B
- 前置依赖Task 1B 完成(可与 1C 并行)
- 执行方式:并行(P1-游戏核心)(与 1C 并行)
- 关键实现细节:
- 实现 `game/enemies/EnemyBase.ts`:怪物基类(血量、移速、路径跟随、受伤、死亡)
- 实现 4 种怪物:
- `game/enemies/FreshGraduate.ts`校招应届生30HP快速数量多
- `game/enemies/OldEmployee.ts`35岁老员工150HP慢速经验护盾
- `game/enemies/TroubleMaker.ts`职业碰瓷王80HP死亡扣20HC
- `game/enemies/BossVP.ts`空降VP800HP组织架构调整技能
- 实现 `game/enemies/WaveManager.ts`波次管理器6波配置、波次间隔、怪物生成
- 实现路径跟随:沿预设路径坐标数组移动,到达终点扣除 KPI
- 实现攻击目标选择:塔选择射程内最近怪物
- 对象池:复用怪物对象,避免频繁 GC
- 怪物头顶显示血条
- 涉及范围:
- `game/enemies/` 目录6个文件
- `game/GameScene.ts`(集成波次管理器)
- 验收标准第1波10只应届生沿S型路径走到终点KPI 正确扣减
- 验证方式手动游玩第1波
---
## Phase 2下一批游戏玩法完整化
**目标:** 实现周报结算、特殊技能、完整6波、胜利/失败界面
- [ ] **Task 2A: 周报结算系统 + 特殊技能**
- 批次:下一批
- 执行方式:并行(P2-玩法)
- 前置依赖Phase 1 全部完成
- 目标:
- 实现周报弹窗第3波结束触发10秒倒计时3个黑话选项
- 实现选对/超时/选错的结果逻辑
- 实现各塔特殊技能:整顿职场、代码屎山、黑话领域、打鸡血
- 实现摸鱼机制点击塔花10HC买咖啡补满精力
- 涉及范围:
- `game/ui/WeeklyReportModal.ts`(周报弹窗)
- `game/data/buzzwords.ts`黑话题库100条
- 各塔文件的特殊技能方法
- 验收标准第3波后弹出周报选对获得奖励特殊技能正常触发
- [ ] **Task 2B: 胜利/失败结算界面 + HUD完善**
- 批次:下一批
- 执行方式:并行(P2-玩法)
- 前置依赖Phase 1 全部完成
- 目标:
- 失败结算仿钉钉退群通知弹窗KPI归零触发
- 胜利结算仿绩效评级界面6波全部通过
- 顶部 HUD 完善KPI 进度条 + HC 数值实时更新
- BOSS 出现特效:全屏红色闪光 + 警告文字
- 怪物头顶语录飘字100条黑话随机显示
- 涉及范围:
- `game/ui/VictoryModal.ts`
- `game/ui/DefeatModal.ts`
- `game/ui/HUD.ts`
- `game/data/quotes.ts`100条语录
---
## Phase 3收尾批体验优化
- [ ] **Task 3: 视觉polish + 适配优化**
- 批次:收尾批
- 前置依赖Phase 2 完成
- 目标:
- Canvas 缩放适配(不同浏览器窗口大小等比缩放)
- CRT 扫描线效果CSS叠加层
- 霓虹发光按钮动效
- 音效模拟Web Audio API可跳过
- 主页视觉完善(游戏截图预览、特性介绍)
---
## 技术关键点
### Phaser.js 在 Next.js 中的集成
```typescript
// app/game/page.tsx
'use client'
import { useEffect, useRef } from 'react'
export default function GamePage() {
const gameRef = useRef<Phaser.Game | null>(null)
useEffect(() => {
// 动态导入 Phaser避免 SSR 报错)
import('phaser').then((Phaser) => {
import('@/game/config').then(({ gameConfig }) => {
gameRef.current = new Phaser.Game(gameConfig)
})
})
return () => {
gameRef.current?.destroy(true)
}
}, [])
return <div id="game-container" className="w-full h-screen" />
}
```
### 对象池模式
```typescript
// game/enemies/EnemyPool.ts
class EnemyPool {
private pool: EnemyBase[] = []
// 从池中获取怪物,没有则创建
acquire(type: EnemyType): EnemyBase { ... }
// 怪物死亡后回收
release(enemy: EnemyBase) { ... }
}
```
### 游戏数值常量
```typescript
// game/constants.ts
export const MAP_COLS = 16
export const MAP_ROWS = 12
export const TILE_SIZE = 48
export const CANVAS_WIDTH = MAP_COLS * TILE_SIZE // 768 (内部逻辑宽度Phaser处理)
export const CANVAS_HEIGHT = MAP_ROWS * TILE_SIZE // 576
// S型路径坐标格子坐标非像素
export const PATH_WAYPOINTS = [
{ x: 0, y: 2 }, // 入口(面试间)
{ x: 7, y: 2 }, // 第一个转折
{ x: 7, y: 9 }, // 第二个转折
{ x: 15, y: 9 }, // 出口(财务室)
]
export const INITIAL_HC = 200
export const INITIAL_KPI = 100
```
---
## 相关上下文
- PRD 文档:`.docs/prd-tower-defense-game.md`
- 设计系统:`design-system/大厂保卫战/MASTER.md`
- 开发规范:`@rules/dev-best-practices.md`
- 原子提交规范:`@rules/atomic-commit.md`
完成开发后,按 `@rules/atomic-commit.md` 规范,将变更按逻辑模块分组提交(禁止 `git add .`),确保所有文件均已 commit 后再结束任务。

View File

@@ -0,0 +1,205 @@
# 《大厂保卫战:最后的打工人》- PRD v1.0
## 1. 产品概述
### 产品定位
一款2D讽刺类塔防小游戏以互联网大厂职场文化为背景用黑色幽默和荒诞策略玩法解构"内卷"现象。游戏嵌入Next.js页面通过纯前端Phaser.js实现无需安装额外软件即可在浏览器中游玩。
### 背景与目标
- 目标用户:互联网从业者、对大厂文化有共鸣的泛玩家
- 核心体验:荒诞、黑色幽默、策略对抗、共情压力
- 解决痛点:让职场压力通过游戏化方式得到释放和自嘲
### 游戏基本信息
- 游戏名称:《大厂保卫战:最后的打工人》(The Last Grinder)
- 类型2D 讽刺类塔防 (TD)
- 平台Web (浏览器),嵌入 Next.js 页面
- 技术实现Phaser.js纯前端游戏框架
---
## 2. 功能需求
### 核心数值体系 (P0)
**HC (Headcount)** - 资源单位(等同于传统塔防的金币)
- 初始值200 HC
- 获取方式:击败怪物 + 每波结束后的基础奖励
**KPI (关键绩效指标)** - 基地生命值
- 初始值100%
- 扣减规则:怪物到达终点时按怪物类型扣减
**精力值 (Stamina)** - 防御塔持续作战能力
- 范围0~100
- 攻击时消耗不攻击时每秒恢复5%
- 归零后进入"摸鱼"状态(停止攻击)
---
### 核心功能 (P0)
#### 1. 第一关地图:人力资源部·降本增效
**地图布局**
- 形状S型办公走廊路径
- 起点:"面试间"(怪物刷出点)
- 终点:"财务室/茶水间"KPI扣除点
- 装饰:代码框、倒下的咖啡杯、"奋斗"横幅
**路径设计格子坐标系16x12格**
```
起点(0,2) → 右行至(7,2) → 转向下至(7,9) → 转向右至(15,9) = 终点
```
#### 2. 防御塔系统
| 塔名称 | 成本 | 攻击类型 | 特殊技能 | 攻击力 | 攻速 |
|--------|------|----------|----------|--------|------|
| 00后实习生 | 50 HC | 单体近战 | 整顿职场5%概率秒杀普通怪每秒1%概率自动离场 | 15 | 1.5/s |
| P6资深开发 | 120 HC | 远程直线 | 代码屎山:子弹附带持续伤害(10/s持续3s) | 30 | 1.0/s |
| PPT大师 | 100 HC | 范围减速 | 黑话领域范围内敌人移速降低40% | 5 | 1.5/s |
| HRBP | 80 HC | 辅助Buff | 打鸡血周围1格内塔攻速+20%,每秒消耗其额外精力 | 0 | - |
#### 3. 敌人波次系统
| 怪物名称 | 血量 | 移速 | KPI扣减 | HC奖励 | 特性 |
|----------|------|------|---------|--------|------|
| 校招应届生 | 30 | 快 | 2% | 10 HC | 成群结队,数量多 |
| 35岁老员工 | 150 | 慢 | 8% | 30 HC | 经验护盾无视前3次攻击 |
| 职业碰瓷王 | 80 | 中等 | 5% | 20 HC | 死亡时扣玩家20 HC劳动仲裁 |
| BOSS: 空降VP | 800 | 慢 | 30% | 150 HC | 技能组织架构调整随机摧毁1个防御塔 |
**波次设计共6波**
- 第1波10只校招应届生
- 第2波8只校招应届生 + 3只35岁老员工
- 第3波周报结算 → 5只35岁老员工 + 3只职业碰瓷王
- 第4波12只校招应届生 + 2只职业碰瓷王
- 第5波6只35岁老员工 + 3只职业碰瓷王
- 第6波Boss周报结算 → 1只空降VP + 4只35岁老员工
#### 4. 周报结算系统每3波触发
- 触发时机第3波结束后、第6波开始前
- 界面全屏弹出10秒倒计时
- 玩法从3个随机互联网黑话中选择1个正确答案
- 结果:
- 选对随机获得50~100 HC 或 全场塔精力补满
- 超时/选错全场塔禁锢3秒
**黑话题库(示例)**
```
赋能 / 对齐 / 颗粒度 / 打通 / 闭环 / 抓手 / 生态 / 赛道 / 护城河 / 降维打击
底层逻辑 / 顶层设计 / 方法论 / 复盘 / 迭代 / 串联 / 拉齐 / 落地 / 沉淀 / 跑通
MVP / ROI / KOL / ToB / ToC / 私域 / 增量 / 存量 / 心智 / 势能
```
#### 5. 摸鱼回复机制
- 塔不攻击时精力自动恢复:+5%/s
- 点击塔消耗10 HC购买"瑞幸咖啡":瞬间补满精力
#### 6. 失败结算界面
仿钉钉/飞书通知样式弹窗:
```
[系统通知] 鉴于您近期的表现未能达成业务闭环,经公司管理层研究决定,
对您进行"毕业"处理。请于5分钟内归还工牌不要带走办公文具。
[领取 N+1] (重新开始) [申请仲裁] (返回主页)
```
#### 7. 胜利结算界面
仿绩效评级样式,显示:
- 最终KPI分数
- 消灭怪物总数
- 剩余HC
- 绩效评级S/A/B/C
---
### 重要功能 (P1)
#### 8. 怪物头顶语录飘字
- 怪物头顶随机显示大厂黑话语录
- 100条随机语录池
- 每个怪物显示1条淡入淡出动画
#### 9. Next.js 主页集成
- 主页展示游戏封面、游戏名、开始按钮
- 游戏画面占据主页核心区域
- 飞书/钉钉质感的极简扁平化UI
---
## 3. 视觉设计规范
### 整体视觉风格
- 扁平化设计2D像素艺术风格
- 色调:灰蓝色调("格子间"氛围),配合荧光绿(代码)、橙红(警报)
### 主题配色方案
- 主色Primary`#1D2D44`(深夜格子间蓝)
- 辅助色Secondary`#3E5C76`(办公室灰蓝)
- 强调色Accent`#FF4E00`(加班警报红)
- 成功色:`#22C55E`KPI绿
- 背景色Background`#0A1628`(深夜办公室)
- 文字色Text`#E2E8F0`
### UI质感参考
- 飞书/钉钉的极简扁平化UI
- 系统通知样式的弹窗
- 进度条组件KPI条、精力条
---
## 4. 终端与体验策略
- 终端范围:`adaptive`
- 判定来源默认策略优先PC兼容平板
- 实施策略:`responsive_layout`,以 1280×720 为基准尺寸,响应式缩放
---
## 5. 非功能需求
### 性能要求
- 60fps流畅运行Phaser.js Canvas 渲染)
- 对象池管理怪物和子弹避免GC卡顿
- 最多同时30个怪物实体
### 技术栈
- 游戏引擎Phaser.js 3.x纯前端npm安装
- 集成方式Next.js Page 中直接挂载 Phaser Game 实例
- 无后端依赖,纯客户端运行
### 兼容性
- Chrome 90+, Firefox 88+, Safari 14+
- 最低分辨率1024×600
---
## 6. 项目计划
### MVP 范围(第一期)
1. Next.js 主页 + 游戏入口
2. 第一关完整实现(地图+6波怪物+4种塔
3. 周报结算系统
4. 失败/胜利结算界面
5. 怪物头顶飘字语录
### 里程碑
- M1游戏基础框架 + 地图渲染 + 路径系统
- M2防御塔系统 + 怪物系统 + 战斗逻辑
- M3周报结算 + 特殊技能 + UI完善
- M4主页集成 + 语录库 + 结算界面
---
## 7. 开放问题
- 音效资源是否需要自制音效当前先用CSS音效模拟或跳过
- 存档系统:是否需要保存游戏进度(当前不做)
- 第二关:暂不规划,第一关完善后迭代

View 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总计 1280x960Phaser会缩放
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 FontsPress 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 后再结束任务。

View File

@@ -0,0 +1,427 @@
# Task 1C+1D: 防御塔系统 + 怪物波次系统
## 任务概要
在已完成的 Phaser.js 游戏框架基础上实现完整的防御塔系统4种塔+部署逻辑+精力管理和怪物波次系统4种怪物+路径寻路+战斗逻辑+KPI扣减
**前置条件**Task 1A+1B 已完成,`game/` 目录已存在,`game/GameScene.ts``game/constants.ts``game/GameManager.ts` 等已实现。
## 技术架构
```
game/
├── constants.ts ← 已存在
├── config.ts ← 已存在
├── GameScene.ts ← 已存在,需要集成新系统
├── GameManager.ts ← 已存在
├── towers/
│ ├── TowerBase.ts ← 新建
│ ├── InternTower.ts ← 新建00后实习生
│ ├── SeniorDevTower.ts ← 新建P6资深开发
│ ├── PPTMasterTower.ts ← 新建PPT大师
│ ├── HRBPTower.ts ← 新建HRBP辅助塔
│ └── TowerManager.ts ← 新建
├── enemies/
│ ├── EnemyBase.ts ← 新建
│ ├── FreshGraduate.ts ← 新建(校招应届生)
│ ├── OldEmployee.ts ← 新建35岁老员工
│ ├── TroubleMaker.ts ← 新建(职业碰瓷王)
│ ├── BossVP.ts ← 新建空降VP
│ ├── EnemyPool.ts ← 新建(对象池)
│ └── WaveManager.ts ← 新建(波次管理器)
└── ui/
├── TowerPanel.ts ← 新建(底部塔选择面板)
└── HUD.ts ← 新建(升级 GameScene 中的 HUD 逻辑)
```
## 实现规范
### 防御塔系统
**`game/towers/TowerBase.ts`**
```typescript
export abstract class TowerBase {
protected scene: Phaser.Scene
public gridX: number
public gridY: number
protected sprite: Phaser.GameObjects.Graphics // 用 Graphics 绘制(无美术资源)
protected staminaBar: Phaser.GameObjects.Graphics
// 数值属性
public readonly cost: number
public readonly attackRange: number // 格子单位
public readonly attackDamage: number
public readonly attackSpeed: number // 每秒攻击次数
public readonly maxStamina: number = 100
public stamina: number = 100
protected attackCooldown: number = 0
protected staminaRegen: number = 5 // 每秒恢复量(不攻击时)
protected isActive: boolean = true // false = 摸鱼状态
constructor(scene, gridX, gridY) { ... }
// 每帧更新
update(delta: number, enemies: EnemyBase[]): void {
this.attackCooldown -= delta
if (this.stamina <= 0) {
this.isActive = false
}
if (!this.isActive) {
// 摸鱼:恢复精力
this.stamina = Math.min(this.maxStamina, this.stamina + this.staminaRegen * delta / 1000)
if (this.stamina > 0) this.isActive = true
this.updateStaminaBar()
return
}
// 找目标并攻击
const target = this.findTarget(enemies)
if (target && this.attackCooldown <= 0) {
this.attack(target)
this.stamina -= 5 // 攻击消耗精力
this.attackCooldown = 1000 / this.attackSpeed
this.updateStaminaBar()
} else if (!target) {
// 没有目标时恢复精力
this.stamina = Math.min(this.maxStamina, this.stamina + this.staminaRegen * delta / 1000)
this.updateStaminaBar()
}
}
abstract attack(target: EnemyBase): void
abstract drawSprite(): void // 用 Graphics 绘制塔的外观
protected findTarget(enemies: EnemyBase[]): EnemyBase | null {
// 找射程内血量最多的怪(或最近怪)
...
}
protected updateStaminaBar(): void {
// 更新精力条颜色和宽度
...
}
// 玩家点击塔时调用花费10HC购买咖啡
buyCoffee(): boolean {
const manager = GameManager.getInstance()
if (manager.spendHC(COFFEE_COST)) {
this.stamina = this.maxStamina
this.isActive = true
this.updateStaminaBar()
return true
}
return false
}
destroy(): void { ... }
}
```
**4 种塔的具体实现:**
`InternTower`00后实习生50HC
- 视觉绿色小人形状Graphics 画)
- 攻击近战射程1格单体15伤害1.5/s
- 特殊技能"整顿职场"每次攻击5%概率秒杀(血量<500的普通怪物
- 被动每秒1%概率直接离场(调用 destroy退还 25HC
- 攻击方式:直接扣血(近战,不需要弹幕)
`SeniorDevTower`P6资深开发120HC
- 视觉:深蓝色方形,顶部有 `</>` 符号
- 攻击远程直线30伤害1.0/s射程5格
- 特殊技能"代码屎山":子弹命中后附加 DOT10伤害/秒持续3秒
- 攻击方式发射子弹Graphics 绘制的绿色代码块),直线飞行
`PPTMasterTower`PPT大师100HC
- 视觉:橙色圆形,有 PPT 图标
- 攻击范围AOE5伤害1.5/s射程3格圆形区域
- 特殊技能"黑话领域"攻击命中的怪物移速降低40%持续2秒
- 攻击方式爆炸效果Graphics 绘制的扩散圆圈),范围内所有怪物受伤
`HRBPTower`HRBP80HC
- 视觉:粉色,心形图案
- 攻击:无直接伤害(辅助塔)
- 特殊技能"打鸡血"每0.5秒给周围1格内的塔攻速+20%叠加BUFF每次BUFF消耗自身5精力
- 辅助方式周期性扫描周围格子找到塔就给BUFF
**`game/towers/TowerManager.ts`**
- 维护所有已部署塔的数组
- 处理建塔请求:检查格子合法性(非路径+未占用扣除HC
- 每帧调用所有塔的 update(delta, enemies)
- 处理塔的点击事件(显示购买咖啡的提示)
**`game/ui/TowerPanel.ts`**(底部塔选择面板,在 Phaser Scene 内用 DOM 或 Phaser.GameObjects 实现):
- 优先使用 HTML DOM 覆盖层(`document.createElement`),绝对定位在 Canvas 底部
- 4个塔卡片显示像素风格图标 + 名称 + 成本
- 当前选中的塔有高亮边框
- HC 不足时显示灰色不可点击状态
- 点击塔卡片后,鼠标进入"建塔模式",下一次点击地图格子时放置塔
---
### 怪物波次系统
**`game/enemies/EnemyBase.ts`**
```typescript
export abstract class EnemyBase {
protected scene: Phaser.Scene
protected sprite: Phaser.GameObjects.Graphics
protected healthBar: Phaser.GameObjects.Graphics
protected quoteText: Phaser.GameObjects.Text // 头顶语录
public maxHp: number
public hp: number
public speed: number // 像素/秒
public readonly kpiDamage: number // 到达终点扣除的 KPI
public readonly hcReward: number // 死亡奖励的 HC
// 路径相关
protected pathPoints: { x: number, y: number }[] // 像素坐标路径
protected currentPathIndex: number = 0
protected distanceTraveled: number = 0
// 状态
public isDead: boolean = false
public isActive: boolean = true
public dotEffects: { damage: number, duration: number, timer: number }[] = [] // DOT效果
public slowEffect: number = 0 // 减速百分比0~1
public slowTimer: number = 0
public shieldCount: number = 0 // 护盾层数(老员工专用)
constructor(scene, pathPoints) { ... }
update(delta: number): void {
if (this.isDead || !this.isActive) return
// 处理DOT效果
this.processDOT(delta)
// 处理减速
if (this.slowTimer > 0) {
this.slowTimer -= delta
if (this.slowTimer <= 0) this.slowEffect = 0
}
// 沿路径移动
this.moveAlongPath(delta)
// 更新血条位置
this.updateHealthBar()
this.updateQuoteText()
}
protected moveAlongPath(delta: number): void {
if (this.currentPathIndex >= this.pathPoints.length - 1) {
// 到达终点
this.reachEnd()
return
}
const target = this.pathPoints[this.currentPathIndex + 1]
const currentSpeed = this.speed * (1 - this.slowEffect)
const distance = currentSpeed * delta / 1000
// 向目标移动
... target distance ...
// 到达当前路径点后切换到下一个
...
}
takeDamage(damage: number): void {
if (this.shieldCount > 0) {
this.shieldCount--
return // 护盾吸收
}
this.hp -= damage
this.updateHealthBar()
if (this.hp <= 0) {
this.die()
}
}
addDOT(damage: number, duration: number): void {
this.dotEffects.push({ damage, duration, timer: duration })
}
addSlow(percent: number, duration: number): void {
this.slowEffect = Math.max(this.slowEffect, percent)
this.slowTimer = Math.max(this.slowTimer, duration)
}
protected die(): void {
this.isDead = true
const manager = GameManager.getInstance()
manager.addHC(this.hcReward)
this.onDeath() // 子类可重写碰瓷王扣HC
this.destroy()
}
protected reachEnd(): void {
const manager = GameManager.getInstance()
manager.reduceKPI(this.kpiDamage)
this.isDead = true
this.destroy()
}
protected onDeath(): void {} // 子类重写
abstract drawSprite(): void
abstract getQuote(): string // 返回该怪物的语录
destroy(): void {
this.sprite?.destroy()
this.healthBar?.destroy()
this.quoteText?.destroy()
}
}
```
**4 种怪物:**
`FreshGraduate`(校招应届生):
- HP: 30, 速度: 120px/s, KPI扣减: 2%, HC奖励: 10
- 护盾: 0
- 视觉小绿点Graphics 小圆)
- 语录随机:["求转正!", "我愿意加班!", "卷!卷!卷!"]
`OldEmployee`35岁老员工
- HP: 150, 速度: 50px/s, KPI扣减: 8%, HC奖励: 30
- 护盾: 3层shieldCount=3前3次攻击无效
- 视觉:大蓝方块
- 语录:["我为公司立过功!", "我有10年经验", "年龄不是问题!"]
`TroubleMaker`(职业碰瓷王):
- HP: 80, 速度: 80px/s, KPI扣减: 5%, HC奖励: 20
- 特殊:死亡时重写 `onDeath()` 扣玩家20 HC劳动仲裁
- 视觉:红色叹号形状
- 语录:["录音笔已开启", "这是违法的!", "我要仲裁!"]
`BossVP`空降VP
- HP: 800, 速度: 40px/s, KPI扣减: 30%, HC奖励: 150
- 技能"组织架构调整"每20秒触发一次随机摧毁场上一个防御塔
- 视觉:大金色六边形,周围有特效
- 语录:["我来教大家怎么做事", "你们缺乏战略眼光", "这不是执行力的问题"]
- BOSS出现时全屏红色闪光效果Phaser Camera flash
**`game/enemies/EnemyPool.ts`**(对象池):
简单实现:维护一个 inactive 数组acquire 时取出复用release 时放回。
**`game/enemies/WaveManager.ts`**(波次管理器):
```typescript
// 6波配置
const WAVE_CONFIG = [
{ enemies: [{ type: 'FreshGraduate', count: 10, interval: 800 }] }, // 第1波
{ enemies: [{ type: 'FreshGraduate', count: 8, interval: 800 }, { type: 'OldEmployee', count: 3, interval: 2000 }] },
{ enemies: [{ type: 'OldEmployee', count: 5, interval: 2000 }, { type: 'TroubleMaker', count: 3, interval: 1500 }] }, // 周报前
{ enemies: [{ type: 'FreshGraduate', count: 12, interval: 600 }, { type: 'TroubleMaker', count: 2, interval: 1500 }] },
{ enemies: [{ type: 'OldEmployee', count: 6, interval: 1500 }, { type: 'TroubleMaker', count: 3, interval: 1500 }] },
{ enemies: [{ type: 'BossVP', count: 1, interval: 0 }, { type: 'OldEmployee', count: 4, interval: 2000 }] }, // Boss波
]
export class WaveManager {
private currentWave: number = 0
private isSpawning: boolean = false
private waveComplete: boolean = false
// 周报触发第3波结束后
private onWave3Complete: () => void
// 胜利第6波全部消灭
private onAllWavesComplete: () => void
startNextWave(): void { ... }
private spawnEnemy(type: string): EnemyBase { ... }
update(delta: number): void { ... } // 每帧更新所有活跃怪物
getAllActiveEnemies(): EnemyBase[] { ... }
}
```
**路径像素坐标计算**
PATH_WAYPOINTS 是格子坐标,需要转换为 Phaser Canvas 像素坐标:
```typescript
// 格子坐标转像素坐标(格子中心)
function gridToPixel(gridX, gridY): { x, y } {
return {
x: gridX * TILE_SIZE + TILE_SIZE / 2,
y: gridY * TILE_SIZE + TILE_SIZE / 2 + HUD_HEIGHT // 加上顶部HUD高度
}
}
```
完整路径像素坐标通过对 PATH_WAYPOINTS 相邻点之间插值生成:
```typescript
// 将 PATH_WAYPOINTS 扩展为完整的转折路径(每个转折点都在路径中)
function buildFullPath(): { x, y }[] {
const points = []
for (let i = 0; i < PATH_WAYPOINTS.length - 1; i++) {
const from = gridToPixel(PATH_WAYPOINTS[i].x, PATH_WAYPOINTS[i].y)
const to = gridToPixel(PATH_WAYPOINTS[i+1].x, PATH_WAYPOINTS[i+1].y)
points.push(from)
points.push(to)
}
// 去重相邻相同点
return points.filter((p, i, arr) =>
i === 0 || p.x !== arr[i-1].x || p.y !== arr[i-1].y
)
}
```
---
### HUD 与战斗整合
更新 `game/GameScene.ts`,集成两个新系统:
1. 在场景 `create()` 中初始化 TowerManager 和 WaveManager
2. 在场景 `update(time, delta)` 中:
- 调用 `towerManager.update(delta, waveManager.getAllActiveEnemies())`
- 调用 `waveManager.update(delta)`
- 更新 HUDKPI条、HC显示
3. 处理格子点击事件:若处于"建塔模式",调用 `towerManager.placeTower(gridX, gridY, selectedTowerType)`
4. 添加"开始下一波"按钮(按钮文字"召唤下一波"
5. 波次开始时显示波次提示文字("第X波来袭"
---
### 视觉规范Graphics 绘制指南,无美术资源)
所有游戏对象用 Phaser.GameObjects.Graphics 绘制:
| 对象 | 形状 | 颜色 |
|------|------|------|
| 00后实习生 | 小圆(r=12) + 十字形身体 | `#22C55E`(绿) |
| P6资深开发 | 方块(24x24) + `</>` 文字 | `#3B82F6`(蓝) |
| PPT大师 | 圆(r=16) + 圆心白点 | `#F59E0B`(橙) |
| HRBP | 菱形(16x16) | `#EC4899`(粉) |
| 校招应届生 | 小圆(r=8) | `#86EFAC`(浅绿) |
| 35岁老员工 | 方块(20x20) + 护盾外框 | `#93C5FD`(浅蓝) |
| 职业碰瓷王 | 三角形 | `#FCA5A5`(浅红) |
| 空降VP | 六边形(r=30) + 金色外框 | `#FBBF24`(金色) |
塔的精力条:宽 40px高 4px黄色 `#F59E0B`,底部深灰 `#374151`
怪物血条:宽 30px高 4px绿→红渐变按血量百分比
---
## 验收标准
1. 可以在地图格子上部署 4 种塔,扣除正确 HC
2. 点击已部署的塔显示精力信息,可以花 10HC 购买咖啡
3. 点击"召唤下一波"按钮,怪物从起点出现并沿 S 型路径移动到终点
4. 塔会自动攻击射程内的怪物
5. 怪物被消灭后奖励 HC到达终点后扣除 KPI
6. KPI 条和 HC 显示实时更新
7. 35岁老员工前 3 次攻击不掉血(护盾)
8. 职业碰瓷王死亡时扣除玩家 20 HC
9. 完整 6 波可以正常触发
## 相关上下文
- 设计系统:`design-system/大厂保卫战/MASTER.md`
- PRD`.docs/prd-tower-defense-game.md`
- 计划文档:`.docs/plans/2026-03-21-tower-defense-game.md`
- Task 1A+1B 的产出(已在 `game/` 目录中)
- 开发规范:`@rules/dev-best-practices.md`**必须先阅读**
完成开发后,按 `@rules/atomic-commit.md` 规范,将变更按逻辑模块分组提交(禁止 `git add .`),确保所有文件均已 commit 后再结束任务。

View File

@@ -0,0 +1,223 @@
# Task 2A+2B: 周报结算系统 + 特殊技能完善 + 胜利失败界面 + 怪物语录
## 任务概要
在已完成的游戏基础框架上实现周报结算弹窗每3波触发、完善各塔特殊技能、实现胜利/失败结算界面、以及怪物头顶语录飘字系统。
**前置条件**Task 1A+1B+1C+1D 已完成,完整的游戏框架已运行。
## 需要了解的已有文件
先读取以下文件了解现有实现:
- `game/GameManager.ts`(游戏状态,了解事件系统接口)
- `game/GameScene.ts`主场景了解如何集成新UI
- `game/ui/HUD.ts`已有HUD了解胜利/失败通知已有实现)
- `game/enemies/WaveManager.ts`(了解波次完成事件是如何触发的)
## 实现内容
### 1. 周报结算弹窗(`game/ui/WeeklyReportModal.ts`
**触发时机**第3波结束后WaveManager 已有 `onWeeklyReport` 回调)
**弹窗设计**(全屏覆盖 DOM 层,仿钉钉/飞书全屏通知):
```
[全屏黑色半透明背景z-index: 9999]
[中央弹窗卡片,深色背景 #1a1a2e霓虹紫边框]
标题:"📊 周报提交时间!"(用 img/SVG 图标代替 emoji或纯文字
副标题:"请选择正确的互联网黑话,提交本周工作总结"
[10秒倒计时进度条] — 顶部红色进度条,从满到空
3个选项卡片随机从黑话题库选3个其中1个是"正确答案"
[选项A] [选项B] [选项C]
答题结果区域(答题后显示):
- 选对:绿色提示 "正确!获得奖励:+80 HC" 或 "全场精力已补满"
- 选错/超时:红色提示 "答错了老板视察3秒全场塔禁锢"
```
**黑话题库**(在 `game/data/buzzwords.ts` 中定义100条
```typescript
// 分为两类:正确答案类(互联网常见黑话)+ 干扰项
export const BUZZWORDS = [
// 正确答案(真实大厂黑话)
"赋能", "对齐", "颗粒度", "打通", "闭环", "抓手", "生态", "赛道",
"护城河", "降维打击", "底层逻辑", "顶层设计", "方法论", "复盘",
"迭代", "串联", "拉齐", "落地", "沉淀", "跑通", "MVP", "ROI",
"私域流量", "增量市场", "存量竞争", "心智占位", "势能积累",
"组织赋能", "生态打通", "战略对齐", "价值共创", "协同增效",
"降本增效", "提质增效", "精益管理", "敏捷开发", "极致体验",
"用户心智", "品牌溢价", "流量变现", "私域运营", "全渠道",
"中台建设", "数字化转型", "智能升级", "生态圈", "护城河",
"弯道超车", "换道超车", "破圈", "出圈", "刷屏", "爆款",
"现象级", "标杆案例", "对标", "copy from", "跑模型",
// 干扰项(故意写错/不通顺的)
"增熵赋能", "横向闭环", "负向对齐", "反底层逻辑",
]
// 每次从 BUZZWORDS 随机取3个其中第一个是"正确答案"
// 随机打乱顺序后展示
export function generateWeeklyOptions(): { options: string[], correctIndex: number } {
const shuffled = [...BUZZWORDS].sort(() => Math.random() - 0.5)
const correct = shuffled[0]
const options = [correct, shuffled[1], shuffled[2]].sort(() => Math.random() - 0.5)
return {
options,
correctIndex: options.indexOf(correct)
}
}
```
**倒计时逻辑**
- 10秒倒计时使用 `setInterval`
- 超时自动触发"选错"结果
- 选择后立即停止倒计时,显示结果 2 秒后自动关闭弹窗
**结果逻辑**
```typescript
// 选对随机50%概率给HC50%概率补满精力
if (Math.random() > 0.5) {
gameManager.addHC(50 + Math.floor(Math.random() * 50))
showResult('success', `获得 ${reward} HC继续加油`)
} else {
// 通知所有塔补满精力(通过 GameScene 的回调)
onFullStamina()
showResult('success', '全场精力已补满!')
}
// 选错/超时触发全场塔禁锢3秒
onBossInspection() // 调用 GameScene 的回调,禁锢所有塔
showResult('error', '老板来视察了全场禁锢3秒')
```
### 2. 完善胜利/失败界面(更新 `game/ui/HUD.ts` 或单独文件)
当前 HUD 可能已有简单的胜利/失败提示,需要升级为完整的模态弹窗。
**失败弹窗**KPI 归零时触发,仿钉钉退群通知):
```
[弹窗容器,白色背景,仿钉钉卡片样式]
[顶部蓝色条] 系统通知
[钉钉风格图标]
正文:
鉴于您近期的表现未能达成业务闭环,
经公司管理层研究决定,
对您进行"毕业"处理。
请于5分钟内归还工牌不要带走办公文具。
[领取 N+1] (重新开始,刷新页面)
[申请仲裁] (返回主页,跳转 /)
```
**胜利弹窗**全6波清空后仿绩效评级系统
```
[弹窗容器,深色背景,金色边框]
标题:绩效评级公示
最终KPI: XX%
消灭怪物: XX只
剩余HC: XX
绩效等级:
- KPI >= 80%: S级 "超出预期"
- KPI >= 60%: A级 "达成预期"
- KPI >= 40%: B级 "基本达成"
- KPI < 40%: C级 "未达预期"
等级对应奖励描述(黑色幽默):
- S级"恭喜晋升为高级打工人!福报已在路上..."
- A级"表现良好明年涨薪3%(扣去通胀后-2%"
- B级"还需努力下月开始996"
- C级"已被纳入待优化名单"
[再战一局] (重新开始)
[见好就收] (返回主页)
```
### 3. 怪物头顶语录飘字(更新 `game/enemies/EnemyBase.ts`
EnemyBase 中的 `quoteText` 字段已预留。现在实现完整的语录系统:
**`game/data/quotes.ts`**100条语录分怪物类型
```typescript
export const QUOTES = {
FreshGraduate: [
"求转正!", "我愿意加班!", "卷!卷!卷!",
"内推有名额吗?", "实习补贴够买咖啡吗?",
"我会CRUD", "熟练掌握Word和Excel",
"我有五年实习经验!", "大厂梦...", "期待来公司学习!",
"我不需要工资,只需要经验!", "比同龄人卷!",
],
OldEmployee: [
"我为公司立过功!", "我有10年经验",
"年龄不是问题!", "那时候还是我搭的架构",
"当年我一个人顶三个人!", "这个需求做不了",
"怎么可能这么快做完!", "文档?从来没有!",
"测试QA负责的", "这是历史遗留问题",
],
TroubleMaker: [
"录音笔已开启", "这是违法的!",
"我要仲裁!", "劳动法第X条规定...",
"我已咨询过律师", "保留证据中...",
"你们的违规操作我都记录了", "看我不告你们!",
],
BossVP: [
"我来教大家怎么做事", "你们缺乏战略眼光",
"这不是执行力的问题", "格局太小了",
"你们都不懂商业本质", "要有全局思维",
"小事不过手,大事全拍板", "你们的方案需要颠覆性重构",
"我在BAT做过这个", "先对齐一下认知",
],
}
```
**语录飘字动效**
- 怪物出生后 0.5 秒显示语录(随机从该类型的语录库中取)
- 字体VT323白色
- 文字在怪物头顶30px处显示
- 3秒后淡出alpha 从1到0的 Tween 动画)
- 文字跟随怪物移动
### 4. 全场塔禁锢效果(`GameScene` 中添加)
当周报答错/超时时,触发"老板视察"
```typescript
// 在 GameScene 中添加
freezeAllTowers(duration: number = 3000): void {
this.towerManager.getAllTowers().forEach(tower => {
tower.isFrozen = true
// 视觉:塔变灰色
setTimeout(() => {
tower.isFrozen = false
// 视觉:恢复正常颜色
}, duration)
})
}
refillAllStamina(): void {
this.towerManager.getAllTowers().forEach(tower => {
tower.stamina = tower.maxStamina
tower.isActive = true
})
}
```
在 TowerBase 的 `update()` 中检查 `isFrozen` 状态,如果为 true 则跳过攻击。
## 验收标准
1. 第3波全部怪物消灭后弹出周报弹窗有10秒倒计时
2. 选对答案随机给予HC奖励或补满精力
3. 选错/超时全场塔3秒无法攻击显示灰色
4. KPI归零时弹出仿钉钉失败弹窗两个按钮功能正确
5. 第6波全部消灭后弹出绩效评级胜利弹窗根据最终KPI显示正确等级
6. 所有怪物头顶有飘字语录随怪物移动3秒后淡出
## 相关上下文
- 设计系统:`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`
完成开发后,按 `@rules/atomic-commit.md` 规范,将变更按逻辑模块分组提交(禁止 `git add .`),确保所有文件均已 commit 后再结束任务。

View File

@@ -0,0 +1,288 @@
# Design System Master File
> **LOGIC:** When building a specific page, first check `design-system/pages/[page-name].md`.
> If that file exists, its rules **override** this Master file.
> If not, strictly follow the rules below.
---
**Project:** 大厂保卫战
**Generated:** 2026-03-21 07:46:37
**Category:** Gaming
---
## Global Rules
### Color Palette
| Role | Hex | CSS Variable |
|------|-----|--------------|
| Primary | `#7C3AED` | `--color-primary` |
| Secondary | `#A78BFA` | `--color-secondary` |
| CTA/Accent | `#F43F5E` | `--color-cta` |
| Background | `#0F0F23` | `--color-background` |
| Text | `#E2E8F0` | `--color-text` |
**Color Notes:** Neon purple + rose action
### Typography
- **Heading Font:** Press Start 2P
- **Body Font:** VT323
- **Mood:** pixel, retro, gaming, 8-bit, nostalgic, arcade
- **Google Fonts:** [Press Start 2P + VT323](https://fonts.google.com/share?selection.family=Press+Start+2P|VT323)
**CSS Import:**
```css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&family=VT323&display=swap');
```
### Spacing Variables
| Token | Value | Usage |
|-------|-------|-------|
| `--space-xs` | `4px` / `0.25rem` | Tight gaps |
| `--space-sm` | `8px` / `0.5rem` | Icon gaps, inline spacing |
| `--space-md` | `16px` / `1rem` | Standard padding |
| `--space-lg` | `24px` / `1.5rem` | Section padding |
| `--space-xl` | `32px` / `2rem` | Large gaps |
| `--space-2xl` | `48px` / `3rem` | Section margins |
| `--space-3xl` | `64px` / `4rem` | Hero padding |
### Shadow Depths
| Level | Value | Usage |
|-------|-------|-------|
| `--shadow-sm` | `0 1px 2px rgba(0,0,0,0.05)` | Subtle lift |
| `--shadow-md` | `0 4px 6px rgba(0,0,0,0.1)` | Cards, buttons |
| `--shadow-lg` | `0 10px 15px rgba(0,0,0,0.1)` | Modals, dropdowns |
| `--shadow-xl` | `0 20px 25px rgba(0,0,0,0.15)` | Hero images, featured cards |
---
## Component Specs
### Buttons
```css
/* Primary Button */
.btn-primary {
background: #F43F5E;
color: white;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 200ms ease;
cursor: pointer;
}
.btn-primary:hover {
opacity: 0.9;
transform: translateY(-1px);
}
/* Secondary Button */
.btn-secondary {
background: transparent;
color: #7C3AED;
border: 2px solid #7C3AED;
padding: 12px 24px;
border-radius: 8px;
font-weight: 600;
transition: all 200ms ease;
cursor: pointer;
}
```
### Cards
```css
.card {
background: #0F0F23;
border-radius: 12px;
padding: 24px;
box-shadow: var(--shadow-md);
transition: all 200ms ease;
cursor: pointer;
}
.card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
```
### Inputs
```css
.input {
padding: 12px 16px;
border: 1px solid #E2E8F0;
border-radius: 8px;
font-size: 16px;
transition: border-color 200ms ease;
}
.input:focus {
border-color: #7C3AED;
outline: none;
box-shadow: 0 0 0 3px #7C3AED20;
}
```
### Modals
```css
.modal-overlay {
background: rgba(0, 0, 0, 0.5);
backdrop-filter: blur(4px);
}
.modal {
background: white;
border-radius: 16px;
padding: 32px;
box-shadow: var(--shadow-xl);
max-width: 500px;
width: 90%;
}
```
---
## Style Guidelines
**Style:** Retro-Futurism
**Keywords:** Vintage sci-fi, 80s aesthetic, neon glow, geometric patterns, CRT scanlines, pixel art, cyberpunk, synthwave
**Best For:** Gaming, entertainment, music platforms, tech brands, artistic projects, nostalgic, cyberpunk
**Key Effects:** CRT scanlines (::before overlay), neon glow (text-shadow+box-shadow), glitch effects (skew/offset keyframes)
### Page Pattern
**Pattern Name:** Horizontal Scroll Journey
- **Conversion Strategy:** Immersive product discovery. High engagement. Keep navigation visible.
28,Bento Grid Showcase,bento, grid, features, modular, apple-style, showcase", 1. Hero, 2. Bento Grid (Key Features), 3. Detail Cards, 4. Tech Specs, 5. CTA, Floating Action Button or Bottom of Grid, Card backgrounds: #F5F5F7 or Glass. Icons: Vibrant brand colors. Text: Dark., Hover card scale (1.02), video inside cards, tilt effect, staggered reveal, Scannable value props. High information density without clutter. Mobile stack.
29,Interactive 3D Configurator,3d, configurator, customizer, interactive, product", 1. Hero (Configurator), 2. Feature Highlight (synced), 3. Price/Specs, 4. Purchase, Inside Configurator UI + Sticky Bottom Bar, Neutral studio background. Product: Realistic materials. UI: Minimal overlay., Real-time rendering, material swap animation, camera rotate/zoom, light reflection, Increases ownership feeling. 360 view reduces return rates. Direct add-to-cart.
30,AI-Driven Dynamic Landing,ai, dynamic, personalized, adaptive, generative", 1. Prompt/Input Hero, 2. Generated Result Preview, 3. How it Works, 4. Value Prop, Input Field (Hero) + 'Try it' Buttons, Adaptive to user input. Dark mode for compute feel. Neon accents., Typing text effects, shimmering generation loaders, morphing layouts, Immediate value demonstration. 'Show, don't tell'. Low friction start.
- **CTA Placement:** Floating Sticky CTA or End of Horizontal Track
- **Section Order:** 1. Intro (Vertical), 2. The Journey (Horizontal Track), 3. Detail Reveal, 4. Vertical Footer
---
## Anti-Patterns (Do NOT Use)
- ❌ Minimalist design
- ❌ Static assets
### Additional Forbidden Patterns
-**Emojis as icons** — Use SVG icons (Heroicons, Lucide, Simple Icons)
-**Missing cursor:pointer** — All clickable elements must have cursor:pointer
-**Layout-shifting hovers** — Avoid scale transforms that shift layout
-**Low contrast text** — Maintain 4.5:1 minimum contrast ratio
-**Instant state changes** — Always use transitions (150-300ms)
-**Invisible focus states** — Focus states must be visible for a11y
---
## 产品定位与目标用户分析
**产品定位:** 面向互联网从业者的2D讽刺类塔防小游戏以"大厂职场文化"为世界观,用黑色幽默和荒诞策略玩法提供情绪出口。
**目标用户:** 25-35岁互联网从业者对内卷/福报/绩效考核有亲身体验,游戏轻度玩家。
**差异化:** 游戏内所有数值、界面、怪物都是职场文化的隐喻,产生强烈共情与自嘲效果。
---
## 布局模式与结构Layout Strategy
**选定模式:** 模式 B — 内容展示型(游戏全屏内容为主)
**页面结构:**
- **主页 `/`**:全屏游戏入口,顶部 Navbar游戏名+状态栏),中央游戏 Canvas底部版权
- **游戏 Canvas 区域**1280x720 基准,等比缩放适配不同分辨率
- **HUD游戏内界面**:叠加在 Canvas 上的 HTML 层KPI 条、HC 显示、塔选择面板)
**页面区域划分:**
```
┌────────────────────────────────────────────────┐
│ [游戏名称] [KPI: 87%] [HC: 320] │ ← Navbar/HUD
├────────────────────────────────────────────────┤
│ │
│ 游戏 Canvas │ ← Phaser.js Canvas (全屏)
│ (地图 + 防御塔 + 怪物 + 弹幕) │
│ │
├────────────────────────────────────────────────┤
│ [00后实习生 50HC] [P6开发 120HC] [PPT大师 100HC] │ ← 底部塔选择栏
└────────────────────────────────────────────────┘
```
**移动端适配:** 优先PC1024px+移动端768px以下保持可玩性使用触摸拖放部署塔
**Nova SDK 组件:** 本项目为纯游戏,不使用 Nova SDK 组件,改用 Phaser.js 引擎
---
## 游戏专属视觉设计
### 颜色覆盖(游戏内专属)
| 用途 | Hex | 说明 |
|------|-----|------|
| 地图格子(可建塔区) | `#1E3A5F` | 深蓝格子 |
| 地图格子(路径) | `#2D1B00` | 深褐走廊 |
| KPI 条(健康) | `#22C55E` | 绿色正常 |
| KPI 条(危险) | `#EF4444` | 红色告警 |
| 精力条 | `#F59E0B` | 橙黄活力 |
| HC 数值 | `#A78BFA` | 紫色资源 |
| BOSS 警告 | `#FF4E00` | 橙红警报 |
### 游戏 UI 组件设计HUD
- **KPI 进度条**:像素风格,带扫描线效果,颜色渐变(绿→黄→红)
- **HC 计数器**:仿钉钉/飞书通知badge样式数字跳动动画
- **塔选择卡片**:飞书卡片质感,深色毛玻璃背景,霓虹边框
- **周报弹窗**:仿钉钉全屏通知,强制交互设计
- **语录飘字**:怪物头顶白色文字,淡入淡出,字体 VT323
- **失败弹窗**:完全仿钉钉退群通知,灰白配色反差
### 关键页面交互设计
1. **主游戏页面**
- 点击地图格子 → 弹出塔选择浮层(若 HC 不足则提示)
- 点击已部署的塔 → 显示精力条 + 购买咖啡按钮
- 波次开始前 3 秒倒计时提示
- BOSS 出现时全屏红色闪光 + 警报音效
2. **周报结算弹窗**
- 全屏遮罩(不可点击背景关闭)
- 10 秒倒计时进度条(顶部)
- 3 个黑话选项卡片,答错/超时变红闪烁
3. **胜利/失败结算**
- 仿绩效系统界面(胜利)
- 仿钉钉退群通知(失败)
---
## Pre-Delivery Checklist
Before delivering any UI code, verify:
- [ ] No emojis used as icons (use SVG instead)
- [ ] All icons from consistent icon set (Heroicons/Lucide)
- [ ] `cursor-pointer` on all clickable elements
- [ ] Hover states with smooth transitions (150-300ms)
- [ ] Light mode: text contrast 4.5:1 minimum
- [ ] Focus states visible for keyboard navigation
- [ ] `prefers-reduced-motion` respected
- [ ] Responsive: 375px, 768px, 1024px, 1440px
- [ ] No content hidden behind fixed navbars
- [ ] No horizontal scroll on mobile
- [ ] 游戏 Canvas 在 1280x720 基准下布局正确
- [ ] 所有 HUD 元素覆盖在 Canvas 正确位置
- [ ] 波次系统正常触发6 波全部可完成
- [ ] 周报结算系统在第 3 波后正确触发