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

11 KiB
Raw Blame History

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()
  • 移除:整个 FlowFieldupdateFlowField(), 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():仅注册 PlayerInputSystemStateSyncSystem移除其他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_CONFIGMAX_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 中的校正逻辑引用了武器状态,需验证精简版是否正常工作