Logo
热心市民王先生

技术实现思路

技术研究 人工智能 API

Vue 3 + TypeScript 作为前端主框架具有以下优势: 1. 响应式系统改进:Vue 3 的 Composition API 提供了更灵活的状态管理方式,特别适合复杂的 Ban/Pick 状态机管理 2. 类型安全:TypeScript 提供强类型支持,减少运行时错误,特别适合团队协作开发 3. 移动端适配:Vue 3 的响应式特性可以很好地适配...

技术栈推荐

前端技术栈

主框架选择

Vue 3 + TypeScript 作为前端主框架具有以下优势:

  1. 响应式系统改进:Vue 3 的 Composition API 提供了更灵活的状态管理方式,特别适合复杂的 Ban/Pick 状态机管理
  2. 类型安全:TypeScript 提供强类型支持,减少运行时错误,特别适合团队协作开发
  3. 移动端适配:Vue 3 的响应式特性可以很好地适配不同屏幕尺寸,配合 CSS 媒体查询实现响应式布局
  4. 生态丰富:Vue 生态系统中有大量现成的动画库(如 Vue2-animate)、UI 组件库(如 Element Plus Mobile)

React 也是一个不错的选择,但考虑到项目需要快速开发和维护,Vue 3 的学习曲线相对平缓,社区中文资源更丰富。在移动端方面,React Native 可能不如 Vue 配合 Vite 构建的 H5 应用来得轻量。

推荐:Vue 3 + TypeScript

状态管理

Pinia + Composables 组合作为状态管理方案:

  1. Pinia:Vue 官方推荐的状态管理库,比 Vuex 更轻量、更易于理解,支持 TypeScript,提供了更好的 DevTools 集成
  2. Composables:Vue 3 的组合式函数,可以将 Ban/Pick 相关的状态逻辑封装为可复用的函数,提高代码复用性

具体的状态管理设计包括:

  • 房间状态:管理房间信息、用户身份、连接状态
  • 选人状态:管理当前阶段、剩余时间、已选球员、已 Ban 球员
  • UI 状态:管理界面显示、动画效果、倒计时等

推荐:Pinia + Composables

动画实现

Framer MotionGSAP 配合 CSS 动画:

  1. Framer Motion:功能强大的动画库,支持手势操作、物理动画,API 直观易用
  2. GSAP:专业的动画库,性能优异,适合复杂的动画序列

对于 Ban/Pick 系统的动画需求,建议使用 GSAP 处理复杂的界面切换动画,CSS 动画处理简单的交互反馈,使用 Lottie 处理复杂的矢量动画(如倒计时效果)。

推荐:GSAP + CSS 动画

WebSocket 客户端

Socket.IO 客户端

  1. 支持自动重连和心跳机制
  2. 提供房间广播功能,方便选人状态同步
  3. 支持命名空间和房间隔离
  4. 有完善的错误处理和降级机制

推荐:Socket.IO 客户端

构建工具

Vite

  1. 开发环境启动速度快,热更新性能好
  2. 对 TypeScript、CSS 预处理器支持完善
  3. 拆包和代码优化能力强,适合 H5 应用
  4. 生态活跃,插件丰富

推荐:Vite

后端技术栈

主框架选择

Node.js + ExpressNestJS

  1. Node.js + Express:轻量、灵活,适合小型到中型项目,开发效率高
  2. NestJS:基于 Express 的企业级框架,提供了更好的代码组织和架构模式,适合大型项目

考虑到项目的实时性要求,推荐使用 NestJS,它内置了 WebSocket 支持,提供了更好的 TypeScript 支持和依赖注入机制,便于后续功能扩展。

推荐:NestJS

WebSocket 服务

Socket.IO 服务端

  1. 与客户端保持一致,便于开发和维护
  2. 提供强大的房间管理和广播功能
  3. 支持中间件和认证机制
  4. 有完善的文档和社区支持

推荐:Socket.IO 服务端

数据存储

Redis + 内存存储

  1. Redis:用于缓存频繁访问的数据(如球员信息)、存储房间状态
  2. 内存存储:用于选人过程中的临时数据存储,配合定时持久化到 Redis

考虑到项目不需要长期存储历史数据,可以优先使用内存存储,Redis 作为持久化和缓存层。

推荐:Redis + 内存存储

关键技术难点

并发控制与状态同步

问题背景

Ban/Pick 系统的核心挑战在于处理两个用户的同时操作。在网络延迟、用户快速操作的情况下,可能出现以下问题:

  1. 操作冲突:双方同时选择同一个球员
  2. 状态不一致:网络延迟导致一方看不到另一方的操作
  3. 超时处理:服务器端倒计时和客户端倒计时的同步问题

解决方案

乐观锁 + 版本控制

  1. 每个房间维护一个版本号(version)
  2. 每个选人操作都携带当前版本号
  3. 服务端验证版本号,如果版本不一致则拒绝操作
  4. 客户端在收到版本冲突时,重新获取最新状态并更新界面

事件溯源模式

  1. 所有选人操作作为事件存储
  2. 按时间顺序回放事件来重建状态
  3. 保证状态重建的一致性

具体实现

// 房间状态结构
interface RoomState {
  version: number;
  currentPlayer: 'home' | 'away';
  phase: 'ban' | 'pick' | 'confirm';
  homePlayers: Player[];
  awayPlayers: Player[];
  bannedPlayers: Player[];
  lastActionTime: number;
}

// 操作消息
interface PickMessage {
  playerId: string;
  roomVersion: number; // 操作时的版本号
  timestamp: number;
}

// 服务端验证
async function handlePick(message: PickMessage) {
  const room = getRoom(message.roomId);
  if (room.version !== message.roomVersion) {
    return { status: 'conflict', currentVersion: room.version };
  }
  
  // 验证操作合法性
  if (room.currentPlayer !== 'home') {
    return { status: 'invalid', reason: 'not_your_turn' };
  }
  
  // 执行操作
  const player = room.availablePlayers.find(p => p.id === message.playerId);
  if (!player) {
    return { status: 'invalid', reason: 'player_not_available' };
  }
  
  // 更新状态
  room.homePlayers.push(player);
  room.availablePlayers = room.availablePlayers.filter(p => p.id !== message.playerId);
  room.version++;
  
  // 广播更新
  broadcastRoomUpdate(room);
}

倒计时同步

服务器主导的倒计时

  1. 倒计时由服务器控制,客户端只显示
  2. 服务器定期广播剩余时间
  3. 客户端收到时间更新后更新本地显示
  4. 网络延迟造成的误差可以通过时间校准解决

心跳检测

  1. 客户端定期向服务器发送心跳包
  2. 服务器检测到用户长时间无响应时,可以主动结束其回合
  3. 处理网络异常情况下的状态恢复

网络异常处理

问题背景

移动网络环境下,用户可能遇到:

  1. 网络切换(WiFi 到 4G)
  2. 信号波动
  3. 应用被系统挂起
  4. 网络完全断开

解决方案

智能重连机制

  1. 断网检测:客户端定期检测连接状态
  2. 渐进式重连:1s、2s、4s、8s 的指数退避算法
  3. 连接恢复后:同步最新状态,补发丢失的操作
  4. 超时处理:长时间无响应,可提醒用户重新连接

状态缓存

  1. 客户端缓存关键状态(当前房间、选人进度)
  2. 重连后从服务器获取最新状态,比对并同步本地状态
  3. 对于已完成的部分操作,避免重复执行

离线标记

  1. 当检测到用户离线时,界面显示离线状态
  2. 允许其他用户继续操作
  3. 用户重新上线后,状态自动同步

性能优化

图片加载优化

懒加载 + 预加载

  1. 球员图片使用懒加载,只加载当前视图的球员
  2. 对于即将显示的球员(如下一批),进行预加载
  3. 图片格式使用 WebP 或 AVIF,减少文件大小
  4. 实现图片缓存策略,避免重复下载

渐进式加载

  1. 先显示低分辨率图片占位
  2. 再加载高分辨率完整图片
  3. 使用模糊效果过渡,提升用户体验

WebSocket 性能优化

消息压缩

  1. 使用 JSON 压缩算法减少消息大小
  2. 对于频繁更新的状态(如倒计时),采用增量更新
  3. 合并多个状态更新为单次消息

连接管理

  1. 单个 WebSocket 连接处理所有消息
  2. 使用房间频道隔离不同房间的消息
  3. 实现连接池管理,避免创建过多连接

动画性能优化

GPU 加速

  1. 使用 transformopacity 属性触发 GPU 加速
  2. 避免频繁修改 widthheightlefttop 属性
  3. 使用 will-change 提示浏览器优化渲染

减少重排重绘

  1. 使用 requestAnimationFrame 协调动画帧
  2. 复用 DOM 元素,避免频繁创建和销毁
  3. 使用 Canvas 绘制复杂动画,如能力值雷达图

架构设计

整体架构

采用微服务架构,但由于项目规模较小,建议采用模块化单体应用架构:

┌─────────────────┐    ┌─────────────────┐
│   H5 Client    │    │   Admin Client   │
│   (Vue 3)      │    │   (Vue 3)       │
└────────┬───────┘    └────────┬─────────┘
         │                    │
         ▼                    ▼
┌─────────────────────────────────────┐
│         WebSocket Server            │
│        (NestJS + Socket.IO)        │
│                                     │
│  ┌─────────────┐ ┌──────────────┐   │
│  │  Room Service │ │  Game Logic │   │
│  └─────────────┘ └──────────────┘   │
│                                     │
│  ┌─────────────┐ ┌──────────────┐   │
│  │   Redis     │ │   Data       │   │
│  │   Cache     │ │   Store      │   │
│  └─────────────┘ └──────────────┘   │
└─────────────────────────────────────┘

数据流设计

选人操作的数据流

  1. 用户点击球员卡片
  2. 前端验证操作合法性(当前回合、球员可选)
  3. 发送 WebSocket 消息到服务器
  4. 服务器验证操作(版本检查、业务规则)
  5. 更新房间状态,广播更新消息
  6. 其他客户端收到更新,刷新界面
  7. 操作完成后,进入下一阶段或下一回合

状态同步的数据流

  1. 服务器维护房间状态
  2. 定期广播状态更新(包含版本号)
  3. 客户端收到更新,比对版本号
  4. 版本不一致时,同步最新状态
  5. 客户端本地状态与服务器保持一致

部署方案

开发环境

本地开发

  1. 使用 Docker Compose 快速搭建开发环境
  2. 前端使用 Vite 开发服务器,支持热更新
  3. 后端使用 NestJS 开发服务器,支持自动重启
  4. Redis 使用 Docker 容器

代码组织

banpick-game/
├── frontend/         # Vue 3 前端项目
│   ├── src/
│   │   ├── components/  # 组件
│   │   ├── composables/ # 组合式函数
│   │   ├── stores/     # Pinia 状态管理
│   │   └── utils/      # 工具函数
├── backend/           # NestJS 后端项目
│   ├── src/
│   │   ├── modules/
│   │   │   ├── room/   # 房间模块
│   │   │   ├── game/   # 游戏逻辑模块
│   │   │   └── user/   # 用户模块
│   │   └── websockets/ # WebSocket 处理
├── data/              # 静态数据(球员信息等)
└── docker-compose.yml # 开发环境配置

生产环境

云原生部署

  1. 使用 Docker 容器化部署
  2. Kubernetes 进行容器编排和自动扩缩容
  3. 使用 Nginx 作为反向代理,处理静态资源
  4. Redis 集群提供高可用缓存

CDN 加速

  1. 球员图片和静态资源使用 CDN 加速
  2. WebSocket 连接直连应用服务器,避免代理延迟

监控日志

  1. 使用 Prometheus + Grafana 监控系统状态
  2. ELK Stack 收集和分析日志
  3. 前端错误上报机制,及时发现和修复问题

安全考虑

数据安全

输入验证

  1. 所有 WebSocket 消息都进行严格验证
  2. 防止 SQL 注入、XSS 攻击
  3. 验证操作的权限和合法性

敏感信息保护

  1. 球员图片等资源使用临时链接,防止盗用
  2. 敏感操作需要二次确认
  3. 防止 CSRF 攻击

通信安全

HTTPS + WSS

  1. 使用 HTTPS 加密 HTTP 请求
  2. 使用 WSS (WebSocket Secure) 加密 WebSocket 连接
  3. 实现证书管理和自动更新

参考资料