Files
zp2/docs/migration-plan-zh.md
2026-07-26 14:41:36 +08:00

257 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 中的校正逻辑引用了武器状态,需验证精简版是否正常工作