# 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 中的校正逻辑引用了武器状态,需验证精简版是否正常工作