11 KiB
11 KiB
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_GAMEROOM_LIST/ROOM_STATE/GAME_STARTED/ERRORPLAYER_INPUT(仅移动:dx, dy, aimX, aimY, seq)GAME_STATE(仅玩家数据)
3.2 测试流程
- 启动后端:
mvn package && java -jar target/*.jar - 启动前端:
npm run dev - 打开两个浏览器标签页
- 标签页1:创建房间 → 标签页2:加入房间 → 标签页1:开始游戏
- 两个玩家应能在 32x32 地图上互相看到对方移动
- WASD 移动响应流畅(客户端预测)
- 玩家与墙壁碰撞正确
待创建文件清单(共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 中的校正逻辑引用了武器状态,需验证精简版是否正常工作