# ZP1 最小化迁移计划

## 目标
将 zp1 重写为 zp2，仅保留：房间管理、地图加载、玩家移动、前端必要显示。技术栈不变（Java + Vite/Three.js），保留 ECS 架构和客户端预测。

## 范围
- **保留**：房间系统、地图加载/渲染、玩家移动（WASD）、客户端预测、WebSocket 通信
- **移除**：僵尸、武器/子弹、炮塔、火焰区域、掉落物、爆炸/特效、HUD、设置界面、地图编辑器、模板系统、对象池

---

## 阶段一：后端骨架

### 1.1 项目结构
```
zp2/backend/
├── pom.xml
└── src/main/java/com/zombie/game/
    ├── GameServerMain.java          # 入口，仅启动 WebSocket 服务器
    ├── model/
    │   ├── Constants.java           # 精简为：GRID_SIZE, TICK_RATE, PLAYER_SIZE, PLAYER_SPEED, MSG_*
    │   ├── Room.java                # 保持原样
    │   ├── PlayerInfo.java          # 保持原样
    │   ├── GameMap.java             # 精简：移除流向场，仅保留 isWall/isWalkable
    │   ├── MapData.java             # 保持，用于地图反序列化
    │   └── StaticWall.java          # 仅保留静态墙
    ├── server/
    │   ├── GameWebSocketServer.java # 精简：房间操作 + 玩家输入 + 状态广播
    │   ├── RoomManager.java         # 保持原样
    │   ├── GameService.java         # 精简：仅注册 PlayerInputSystem + StateSyncSystem
    │   ├── GameLoop.java            # 保持原样（30 TPS）
    │   ├── MessageUtils.java        # 保持原样
    │   └── MapStorage.java          # 保留，用于加载地图文件
    ├── ecs/
    │   ├── ECSWorld.java            # 精简：仅管理 players，移除僵尸/子弹/掉落物/炮塔/火焰区域
    │   ├── System.java              # 保持接口
    │   └── components/
    │       ├── Position.java        # 保持
    │       ├── PlayerInput.java     # 精简：移除手雷相关字段
    │       ├── Health.java          # 精简
    │       ├── Collision.java       # 保持
    │       └── RenderInfo.java      # 精简
    └── systems/
        ├── PlayerInputSystem.java   # 保持：移动 + 碰撞 + 朝向
        └── StateSyncSystem.java     # 精简：仅广播玩家位置
```

### 1.2 关键变更

**Constants.java**
- 保留：`GRID_SIZE=32`, `TICK_RATE=30`, `PLAYER_SIZE=0.8f`, `PLAYER_SPEED=5.0f`, `MSG_*` 消息类型常量
- 移除：`ZOMBIE_SIZE`, `LOOT_*`, 武器常量

**GameMap.java**
- 保留：`loadFromJson()`, `isWall()`, `isWalkable()`, `getCells()`, `getSpawnPoints()`
- 移除：整个 `FlowField`，`updateFlowField()`, `getFlowDirection()`, `addNutWall()`, 坚果墙逻辑
- 仅保留 `StaticWall`（移除 `NutWall`, `TurretWall`）

**ECSWorld.java**
- 保留：`entities`, `players`, `playerIdToEntity`, `map`, `systems`, `lock`
- 移除：`zombies`, `playerBullets`, `zombieBullets`, `loots`, `fireZones`, `turrets`, `wallEntities`
- 移除：所有对象池
- 移除：`createZombieEntity()`, `createBulletEntity()`, `createGrenadeEntity()`, `createMolotovEntity()`, `createLootEntity()`, `createFireZoneEntity()`, `createTurretEntity()`
- 保留：`createPlayerEntity()`（精简版，无 WeaponState/RespawnState）
- 保留：`update(dt)` — 清理临时数据，遍历系统执行

**GameService.java**
- `startGame()`：仅注册 `PlayerInputSystem` 和 `StateSyncSystem`（移除其他10个系统）
- 保留：`processPlayerInput()`, `stopGame()`

**PlayerInputSystem.java**
- 保留：移动（dx/dy * speed）、逐轴墙壁碰撞、朝向计算
- 移除：武器射击逻辑（如有）

**StateSyncSystem.java**
- 精简广播为：`{players: [{id, x, y, angle, health}], gameTime}`
- 移除：zombies, bullets, zombieBullets, loots, explosions, removedBullets, waveNumber, score

**Room.java / RoomManager.java / GameLoop.java / MessageUtils.java**
- 保持原样（或微调清理）

**GameWebSocketServer.java**
- 保留：`onMessage()` 分发、房间 CRUD 处理、`handlePlayerInput()`、`broadcastGameState()`
- 可选移除：房间列表广播定时器（或保留用于大厅刷新）

### 1.3 地图数据
- 保留 `maps/d540209a.json` 格式（walls + playerSpawns + zombieSpawns）
- 复制一份到 `zp2/maps/`

---

## 阶段二：前端骨架

### 2.1 项目结构
```
zp2/frontend/
├── package.json                     # 同样依赖（three, vite）
├── vite.config.js                   # 同样代理配置
├── index.html                       # 同样最小化外壳
└── src/
    ├── main.js                      # 精简：大厅 → 游戏切换
    ├── style.css                    # 仅大厅 + 房间 + 画布样式
    ├── game/
    │   ├── engine.js                # 精简：仅玩家，无僵尸/子弹/战斗
    │   └── scene.js                 # 精简：仅地图 + 玩家，无特效
    ├── network/
    │   └── client.js                # 保持原样
    ├── ui/
    │   └── lobby.js                 # 保持原样（房间管理 UI）
    └── utils/
        ├── constants.js             # 精简：仅地图 + 玩家 + 网络常量
        ├── grid.js                  # 精简：仅 Grid 类 + generateDefaultMap
        └── input.js                 # 精简：仅移动 + 瞄准
```

### 2.2 关键变更

**constants.js**
- 保留：`GRID_SIZE`, `CELL_SIZE`, `PLAYER_SIZE`, `TICK_RATE`, `TICK_INTERVAL`
- 保留：`PLAYER_CONFIG`（MAX_HEALTH, SPEED）
- 保留：`MSG_TYPE`（所有房间 + 游戏消息类型）
- 移除：`WEAPONS`, `WEAPON_CONFIG`, `ZOMBIE_CONFIG`, `ZOMBIE_SIZE`

**grid.js**
- 保留：`Grid` 类的 `parseMap()`, `isWall()`, `worldToGrid()`, `gridToWorld()`, `isWalkable()`
- 保留：`generateDefaultMap()`（备用默认地图）
- 移除：`findPath()`, `getSpawnPoints()`, `isSpawnPoint()`

**input.js**
- 保留：`attach()`, `detach()`, `getMovement()`, `buildInputState()`（仅移动 + 瞄准）
- 移除：`getSelectedWeapon()`, 武器快捷键绑定
- 精简 `buildInputState()` 返回 `{seq, dx, dy, aimX, aimY}`（无 firing, weaponIndex, grenade 字段）

**engine.js（约666→250行）**
- 保留：`connect()`, `start()`, `stop()`, `_loop()`, `_tick()`
- 保留：`_applyLocalPrediction()` — 带碰撞的移动预测
- 保留：`_reconcileLocalPlayer()` — 服务器校正
- 保留：`_initPlayers()`, `_addPlayer()`, `_removePlayer()`
- 精简 `_processServerState()`：仅同步玩家位置，移除所有僵尸/子弹/掉落物/炮塔/特效处理
- 移除：`_handleGrenadeCharge()`, `_checkBulletHit()`, 武器状态, 手雷状态
- 移除：`zombies`, `bullets`, `zombieBullets`, `loots`, `turrets` 映射表

**scene.js（约1331→250行）**
- 保留：构造函数（场景、相机、渲染器、灯光、窗口自适应）
- 保留：`buildMap(mapData)` — 地板 + 墙壁
- 保留：`createPlayerModel()`, `addPlayer()`, `removePlayer()`, `updatePlayer()`
- 保留：`updateCamera()`, `getMouseGroundPos()`, `render()`
- 移除：所有僵尸渲染（约180行）
- 移除：所有子弹渲染（约230行）
- 移除：所有特效（约250行）
- 移除：炮塔、掉落物、坚果墙、手雷目标指示器（约215行）
- 移除：`updateEffects()`（或简化为空）

**lobby.js** — 保持原样

**main.js**
- 保留：App 类、大厅绑定、游戏开始切换
- 移除：HUD 初始化、设置界面初始化
- 移除：`_updateHUD()` 调用

**style.css**
- 保留：大厅样式、房间样式、画布容器样式
- 移除：HUD 样式、武器面板、手雷充能、击杀信息、设置弹窗

---

## 阶段三：清理与验证

### 3.1 消息协议验证
确保以下消息端到端正常工作：
- `CREATE_ROOM` / `JOIN_ROOM` / `LEAVE_ROOM` / `READY` / `START_GAME`
- `ROOM_LIST` / `ROOM_STATE` / `GAME_STARTED` / `ERROR`
- `PLAYER_INPUT`（仅移动：dx, dy, aimX, aimY, seq）
- `GAME_STATE`（仅玩家数据）

### 3.2 测试流程
1. 启动后端：`mvn package && java -jar target/*.jar`
2. 启动前端：`npm run dev`
3. 打开两个浏览器标签页
4. 标签页1：创建房间 → 标签页2：加入房间 → 标签页1：开始游戏
5. 两个玩家应能在 32x32 地图上互相看到对方移动
6. WASD 移动响应流畅（客户端预测）
7. 玩家与墙壁碰撞正确

---

## 待创建文件清单（共36个）

### 后端（23个文件）
| 序号 | 文件 | 来源 |
|------|------|------|
| 1 | `backend/pom.xml` | 从 zp1 复制 |
| 2 | `GameServerMain.java` | 精简版 |
| 3 | `model/Constants.java` | 精简版 |
| 4 | `model/Room.java` | 基本保持 |
| 5 | `model/PlayerInfo.java` | 基本保持 |
| 6 | `model/GameMap.java` | 精简版（无流向场） |
| 7 | `model/MapData.java` | 基本保持 |
| 8 | `model/StaticWall.java` | 基本保持 |
| 9 | `ecs/System.java` | 保持 |
| 10 | `ecs/ECSWorld.java` | 精简版 |
| 11 | `ecs/components/Position.java` | 保持 |
| 12 | `ecs/components/PlayerInput.java` | 精简版 |
| 13 | `ecs/components/Health.java` | 精简版 |
| 14 | `ecs/components/Collision.java` | 保持 |
| 15 | `ecs/components/RenderInfo.java` | 精简版 |
| 16 | `systems/PlayerInputSystem.java` | 基本保持 |
| 17 | `systems/StateSyncSystem.java` | 精简版 |
| 18 | `server/GameWebSocketServer.java` | 精简版 |
| 19 | `server/RoomManager.java` | 基本保持 |
| 20 | `server/GameService.java` | 精简版 |
| 21 | `server/GameLoop.java` | 基本保持 |
| 22 | `server/MessageUtils.java` | 保持 |
| 23 | `server/MapStorage.java` | 基本保持 |

### 前端（12个文件）
| 序号 | 文件 | 来源 |
|------|------|------|
| 24 | `frontend/package.json` | 保持 |
| 25 | `frontend/vite.config.js` | 保持 |
| 26 | `frontend/index.html` | 保持 |
| 27 | `frontend/src/main.js` | 精简版 |
| 28 | `frontend/src/style.css` | 精简版 |
| 29 | `frontend/src/game/engine.js` | 精简版 |
| 30 | `frontend/src/game/scene.js` | 精简版 |
| 31 | `frontend/src/network/client.js` | 基本保持 |
| 32 | `frontend/src/ui/lobby.js` | 保持 |
| 33 | `frontend/src/utils/constants.js` | 精简版 |
| 34 | `frontend/src/utils/grid.js` | 精简版 |
| 35 | `frontend/src/utils/input.js` | 精简版 |

### 数据文件（1个）
| 序号 | 文件 | 来源 |
|------|------|------|
| 36 | `maps/d540209a.json` | 从 zp1 复制 |

---

## 关键设计决策

| 决策 | 选择 | 原因 |
|------|------|------|
| 技术栈 | Java 17 + Vite + Three.js | 与 zp1 一致，迁移成本最低 |
| ECS 架构 | 保留 | 结构清晰，便于后续扩展 |
| 客户端预测 | 保留 | 移动手感更好，代码量不大 |
| 流向场寻路 | 移除 | 仅僵尸 AI 需要 |
| 地图格式 | 保持 JSON | 兼容现有地图文件 |
| WebSocket 协议 | 保持相同消息类型 | 前后端保持同步 |
| 大厅 UI | 保持原样 | 房间管理是核心功能 |
| HUD/设置 | 移除 | 不在本次范围内 |
| 地图编辑器 | 移除 | 不在本次范围内 |

## 风险点
- **StateSyncSystem**：精简时需小心处理消息格式，确保前端能正确解析
- **ECSWorld**：移除组件映射表后，需检查所有引用这些组件的系统
- **客户端预测**：engine.js 中的校正逻辑引用了武器状态，需验证精简版是否正常工作
