668 lines
15 KiB
Markdown
668 lines
15 KiB
Markdown
# 打飞机小程序技术选型与功能架构设计文档
|
||
|
||
> **撰写人**: 移动端产品架构专家 | 苹果设计奖获得者
|
||
> **文档版本**: v1.0
|
||
> **创建日期**: 2024年9月11日
|
||
> **项目**: 打飞机对战小程序
|
||
|
||
## 1. 项目概述与原型分析
|
||
|
||
### 1.1 核心功能模块
|
||
基于原型设计分析,项目包含以下核心功能:
|
||
|
||
**页面结构**:
|
||
- 入口页面:用户登录、游戏模式选择
|
||
- 房间管理:创建房间、加入房间、房间等待
|
||
- 游戏核心:飞机布置、实时对战
|
||
- 用户系统:个人信息、战绩统计
|
||
|
||
**设计特色**:
|
||
- 深色科技主题UI设计
|
||
- 移动优先的交互体验
|
||
- 高度优化的触控操作
|
||
- 实时对战能力
|
||
|
||
### 1.2 MVP原则遵循
|
||
严格按照原型设计实现,不增加额外功能:
|
||
- 基础双人对战游戏
|
||
- 房间制匹配模式
|
||
- 简洁用户界面
|
||
- 核心游戏机制
|
||
|
||
## 2. 技术选型方案
|
||
|
||
### 2.1 前端技术栈
|
||
|
||
#### 2.1.1 小程序框架选择
|
||
**推荐:Taro 4.x + React 18**
|
||
|
||
```typescript
|
||
// 技术栈配置
|
||
{
|
||
"framework": "Taro 4.x",
|
||
"ui": "React 18 + TypeScript",
|
||
"css": "Sass + CSS Modules",
|
||
"state": "Zustand",
|
||
"http": "Taro.request + axios适配",
|
||
"websocket": "Taro WebSocket API"
|
||
}
|
||
```
|
||
|
||
**选择理由**:
|
||
- 一码多端,可快速扩展到H5/APP
|
||
- React生态成熟,组件复用度高
|
||
- TypeScript保证代码质量
|
||
- 与原型设计的现代化风格匹配
|
||
|
||
#### 2.1.2 状态管理
|
||
**Zustand** - 轻量级状态管理
|
||
|
||
```typescript
|
||
// 游戏状态Store结构
|
||
interface GameStore {
|
||
// 用户状态
|
||
user: UserInfo | null
|
||
// 房间状态
|
||
room: RoomInfo | null
|
||
// 游戏状态
|
||
gameState: GameState | null
|
||
// 连接状态
|
||
connectionState: 'connected' | 'connecting' | 'disconnected'
|
||
}
|
||
```
|
||
|
||
#### 2.1.3 UI组件设计
|
||
基于原型的深色科技主题:
|
||
|
||
```scss
|
||
// 设计Token
|
||
$primary-color: #6366f1;
|
||
$secondary-color: #40e0d0;
|
||
$bg-primary: #0f1419;
|
||
$gradient-bg: linear-gradient(135deg, #0f0f1a 0%, #1a1a2e 30%, #16213e 70%, #0f3460 100%);
|
||
```
|
||
|
||
### 2.2 后端技术架构
|
||
|
||
#### 2.2.1 服务端选择
|
||
**Node.js + TypeScript + Fastify**
|
||
|
||
```typescript
|
||
// 服务端架构
|
||
{
|
||
"runtime": "Node.js 18+",
|
||
"framework": "Fastify",
|
||
"language": "TypeScript",
|
||
"websocket": "ws + socket.io",
|
||
"database": "MongoDB + Redis",
|
||
"deployment": "Docker + PM2"
|
||
}
|
||
```
|
||
|
||
**架构优势**:
|
||
- 高性能异步处理
|
||
- WebSocket原生支持
|
||
- TypeScript类型安全
|
||
- 快速开发迭代
|
||
|
||
#### 2.2.2 数据存储设计
|
||
|
||
```typescript
|
||
// MongoDB数据模型
|
||
interface User {
|
||
_id: ObjectId
|
||
openid: string
|
||
nickname: string
|
||
avatar: string
|
||
stats: {
|
||
totalGames: number
|
||
wins: number
|
||
winRate: number
|
||
}
|
||
createdAt: Date
|
||
}
|
||
|
||
interface Room {
|
||
_id: ObjectId
|
||
roomCode: string
|
||
hostId: string
|
||
guestId?: string
|
||
status: 'waiting' | 'playing' | 'finished'
|
||
gameData?: GameData
|
||
createdAt: Date
|
||
}
|
||
|
||
interface GameSession {
|
||
_id: ObjectId
|
||
roomId: string
|
||
players: [string, string]
|
||
gameState: GameStateData
|
||
moves: Move[]
|
||
result?: GameResult
|
||
}
|
||
```
|
||
|
||
```redis
|
||
// Redis缓存策略
|
||
ROOM:{roomCode} -> RoomData (TTL: 1小时)
|
||
USER_ONLINE:{userId} -> ConnectionInfo (TTL: 30分钟)
|
||
GAME_SESSION:{sessionId} -> GameState (TTL: 2小时)
|
||
```
|
||
|
||
### 2.3 实时通信方案
|
||
|
||
#### 2.3.1 WebSocket架构
|
||
基于原型的实时对战需求:
|
||
|
||
```typescript
|
||
// WebSocket消息协议
|
||
interface GameMessage {
|
||
type: 'JOIN_ROOM' | 'PLACE_PLANES' | 'ATTACK' | 'GAME_STATE_SYNC'
|
||
roomCode: string
|
||
userId: string
|
||
data: any
|
||
timestamp: number
|
||
}
|
||
|
||
// 实时功能支持
|
||
- 房间状态同步
|
||
- 对手攻击实时显示(原型中的实时瞄准提示)
|
||
- 游戏状态广播
|
||
- 断线重连机制
|
||
```
|
||
|
||
## 3. 核心功能架构设计
|
||
|
||
### 3.1 游戏核心逻辑
|
||
|
||
#### 3.1.1 飞机模型设计
|
||
基于原型设计需求:
|
||
|
||
```typescript
|
||
// 飞机几何模型
|
||
interface Plane {
|
||
id: string
|
||
center: Position
|
||
direction: 'UP' | 'DOWN' | 'LEFT' | 'RIGHT'
|
||
positions: Position[] // 11个位置
|
||
isDestroyed: boolean
|
||
parts: {
|
||
head: Position
|
||
wings: Position[] // 5个位置
|
||
body: Position[] // 2个位置
|
||
tail: Position[] // 3个位置
|
||
}
|
||
}
|
||
|
||
// 10x10棋盘表示
|
||
interface GameBoard {
|
||
cells: Cell[][] // 10x10网格
|
||
planes: Plane[] // 3架飞机
|
||
}
|
||
|
||
interface Cell {
|
||
position: Position
|
||
state: 'EMPTY' | 'PLANE_PART' | 'ATTACKED_MISS' | 'ATTACKED_HIT'
|
||
planeId?: string
|
||
}
|
||
```
|
||
|
||
#### 3.1.2 攻击逻辑
|
||
```typescript
|
||
// 攻击结果类型
|
||
interface AttackResult {
|
||
type: 'MISS' | 'HIT' | 'DESTROY'
|
||
position: Position
|
||
planeId?: string
|
||
gameEnded?: boolean
|
||
winner?: string
|
||
}
|
||
|
||
// 攻击处理逻辑
|
||
class GameEngine {
|
||
processAttack(
|
||
board: GameBoard,
|
||
position: Position
|
||
): AttackResult {
|
||
// 1. 检查位置有效性
|
||
// 2. 判断攻击结果(miss/hit/destroy)
|
||
// 3. 更新游戏状态
|
||
// 4. 检查游戏结束条件
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.2 页面功能模块
|
||
|
||
#### 3.2.1 入口页面模块
|
||
基于 [`01_入口页面.html`](01_文档/原型设计/01_入口页面.html) 设计:
|
||
|
||
```typescript
|
||
// 入口页面功能
|
||
interface EntryPageFeatures {
|
||
// 用户信息显示
|
||
userProfile: {
|
||
avatar: string
|
||
nickname: string
|
||
level?: number
|
||
}
|
||
|
||
// 游戏模式选择
|
||
gameMode: {
|
||
quickStart: () => void // AI对战
|
||
onlineMatch: () => void // 自动匹配
|
||
createRoom: () => void // 创建房间
|
||
joinGame: () => void // 加入游戏
|
||
}
|
||
|
||
// 游戏规则显示
|
||
rulesDisplay: boolean
|
||
}
|
||
```
|
||
|
||
#### 3.2.2 房间管理模块
|
||
基于原型设计的房间功能:
|
||
|
||
```typescript
|
||
// 房间管理功能
|
||
interface RoomManager {
|
||
// 创建房间
|
||
createRoom(): Promise<{roomCode: string}>
|
||
|
||
// 加入房间
|
||
joinRoom(roomCode: string): Promise<boolean>
|
||
|
||
// 房间状态同步
|
||
syncRoomState(): void
|
||
|
||
// 玩家准备状态
|
||
setPlayerReady(ready: boolean): void
|
||
}
|
||
```
|
||
|
||
#### 3.2.3 游戏对战模块
|
||
基于原型的对战页面设计:
|
||
|
||
```typescript
|
||
// 对战功能模块
|
||
interface BattleModule {
|
||
// 飞机布置阶段
|
||
placementPhase: {
|
||
placePlane(center: Position, direction: Direction): boolean
|
||
autoPlace(): void
|
||
confirmPlacement(): void
|
||
}
|
||
|
||
// 攻击阶段
|
||
attackPhase: {
|
||
selectTarget(position: Position): void
|
||
confirmAttack(): void
|
||
showAttackResult(result: AttackResult): void
|
||
}
|
||
|
||
// 实时功能(原型中的实时瞄准显示)
|
||
realTimeFeatures: {
|
||
showOpponentAiming(position: Position): void
|
||
hideOpponentAiming(): void
|
||
syncGameState(): void
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3.3 数据流架构
|
||
|
||
#### 3.3.1 状态管理流程
|
||
```
|
||
用户操作 -> Action派发 -> Store更新 -> 组件重渲染
|
||
|
|
||
WebSocket同步
|
||
|
|
||
服务端处理 -> 状态广播 -> 对手端更新
|
||
```
|
||
|
||
#### 3.3.2 游戏流程设计
|
||
基于原型页面流程:
|
||
|
||
```typescript
|
||
// 游戏状态机
|
||
enum GamePhase {
|
||
WAITING = 'waiting', // 等待对手
|
||
PLACING = 'placing', // 布置飞机
|
||
BATTLING = 'battling', // 对战中
|
||
FINISHED = 'finished' // 游戏结束
|
||
}
|
||
|
||
// 回合控制
|
||
interface TurnManager {
|
||
currentPlayer: string
|
||
phase: GamePhase
|
||
timeLimit: number
|
||
switchTurn(): void
|
||
checkGameEnd(): boolean
|
||
}
|
||
```
|
||
|
||
## 4. 技术实现细节
|
||
|
||
### 4.1 小程序适配策略
|
||
|
||
#### 4.1.1 页面路由设计
|
||
```typescript
|
||
// 页面路由配置
|
||
const pages = [
|
||
'pages/entry/index', // 入口页面
|
||
'pages/room/create', // 创建房间
|
||
'pages/room/join', // 加入房间
|
||
'pages/room/waiting', // 等待房间
|
||
'pages/game/prepare', // 准备页面
|
||
'pages/game/battle' // 对战页面
|
||
]
|
||
|
||
// 路由管理
|
||
class Navigator {
|
||
static toRoomCreate() {
|
||
wx.navigateTo({ url: '/pages/room/create' })
|
||
}
|
||
|
||
static toGameBattle(roomCode: string) {
|
||
wx.navigateTo({
|
||
url: `/pages/game/battle?roomCode=${roomCode}`
|
||
})
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.1.2 原生API集成
|
||
```typescript
|
||
// 微信小程序API封装
|
||
class WxAPI {
|
||
// 用户授权
|
||
static async getUserInfo(): Promise<UserInfo> {
|
||
const {userInfo} = await wx.getUserProfile({
|
||
desc: '用于显示用户信息'
|
||
})
|
||
return userInfo
|
||
}
|
||
|
||
// 震动反馈(基于原型的触觉反馈)
|
||
static vibrate(): void {
|
||
wx.vibrateShort({ type: 'light' })
|
||
}
|
||
|
||
// 分享功能
|
||
static onShareAppMessage() {
|
||
return {
|
||
title: '打飞机对战',
|
||
path: '/pages/entry/index'
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.2 性能优化方案
|
||
|
||
#### 4.2.1 渲染优化
|
||
基于原型的复杂UI需求:
|
||
|
||
```typescript
|
||
// 游戏棋盘优化渲染
|
||
class BoardRenderer {
|
||
private shouldUpdate = false
|
||
private renderQueue: Position[] = []
|
||
|
||
// 批量更新棋盘状态
|
||
batchUpdateCells(updates: CellUpdate[]): void {
|
||
updates.forEach(update => {
|
||
this.renderQueue.push(update.position)
|
||
})
|
||
|
||
if (!this.shouldUpdate) {
|
||
this.shouldUpdate = true
|
||
this.nextTick(() => this.flushUpdates())
|
||
}
|
||
}
|
||
|
||
private flushUpdates(): void {
|
||
// 批量DOM更新
|
||
this.renderQueue.forEach(pos => this.updateCell(pos))
|
||
this.renderQueue = []
|
||
this.shouldUpdate = false
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 4.2.2 网络优化
|
||
```typescript
|
||
// 请求优化和缓存
|
||
class NetworkManager {
|
||
private cache = new Map<string, any>()
|
||
private pending = new Map<string, Promise<any>>()
|
||
|
||
async request<T>(
|
||
url: string,
|
||
options?: RequestOptions
|
||
): Promise<T> {
|
||
const cacheKey = `${url}:${JSON.stringify(options)}`
|
||
|
||
// 检查缓存
|
||
if (this.cache.has(cacheKey)) {
|
||
return this.cache.get(cacheKey)
|
||
}
|
||
|
||
// 检查pending请求
|
||
if (this.pending.has(cacheKey)) {
|
||
return this.pending.get(cacheKey)
|
||
}
|
||
|
||
// 发起新请求
|
||
const promise = this.makeRequest<T>(url, options)
|
||
this.pending.set(cacheKey, promise)
|
||
|
||
try {
|
||
const result = await promise
|
||
this.cache.set(cacheKey, result)
|
||
return result
|
||
} finally {
|
||
this.pending.delete(cacheKey)
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4.3 错误处理和监控
|
||
|
||
#### 4.3.1 错误边界
|
||
```typescript
|
||
// React错误边界组件
|
||
class GameErrorBoundary extends React.Component {
|
||
state = { hasError: false, error: null }
|
||
|
||
static getDerivedStateFromError(error: Error) {
|
||
return { hasError: true, error }
|
||
}
|
||
|
||
componentDidCatch(error: Error, errorInfo: ErrorInfo) {
|
||
// 错误上报
|
||
this.reportError(error, errorInfo)
|
||
}
|
||
|
||
private reportError(error: Error, errorInfo: ErrorInfo) {
|
||
// 上报到监控系统
|
||
wx.reportMonitor('game_error', {
|
||
error: error.message,
|
||
stack: error.stack,
|
||
componentStack: errorInfo.componentStack
|
||
})
|
||
}
|
||
|
||
render() {
|
||
if (this.state.hasError) {
|
||
return <ErrorFallback onRetry={() => this.setState({ hasError: false })} />
|
||
}
|
||
|
||
return this.props.children
|
||
}
|
||
}
|
||
```
|
||
|
||
## 5. 部署和运维方案
|
||
|
||
### 5.1 开发环境配置
|
||
```json
|
||
{
|
||
"scripts": {
|
||
"dev": "taro build --type weapp --watch",
|
||
"build": "taro build --type weapp",
|
||
"build:h5": "taro build --type h5",
|
||
"deploy": "npm run build && npm run upload"
|
||
},
|
||
"dependencies": {
|
||
"@tarojs/taro": "^4.0.0",
|
||
"@tarojs/plugin-react": "^4.0.0",
|
||
"react": "^18.2.0",
|
||
"zustand": "^4.4.0"
|
||
}
|
||
}
|
||
```
|
||
|
||
### 5.2 服务端部署
|
||
```dockerfile
|
||
# 服务端Docker配置
|
||
FROM node:18-alpine
|
||
WORKDIR /app
|
||
COPY package*.json ./
|
||
RUN npm ci --only=production
|
||
COPY . .
|
||
EXPOSE 3000
|
||
CMD ["node", "dist/server.js"]
|
||
```
|
||
|
||
```yaml
|
||
# docker-compose.yml
|
||
version: '3.8'
|
||
services:
|
||
game-server:
|
||
build: .
|
||
ports:
|
||
- "3000:3000"
|
||
environment:
|
||
- NODE_ENV=production
|
||
- MONGODB_URI=${MONGODB_URI}
|
||
- REDIS_URI=${REDIS_URI}
|
||
depends_on:
|
||
- mongodb
|
||
- redis
|
||
|
||
mongodb:
|
||
image: mongo:6.0
|
||
volumes:
|
||
- mongo_data:/data/db
|
||
|
||
redis:
|
||
image: redis:7-alpine
|
||
volumes:
|
||
- redis_data:/data
|
||
```
|
||
|
||
### 5.3 监控和日志
|
||
```typescript
|
||
// 游戏性能监控
|
||
class PerformanceMonitor {
|
||
// 游戏关键指标监控
|
||
trackGameMetrics() {
|
||
// 游戏启动时间
|
||
const startTime = Date.now()
|
||
|
||
// 页面加载性能
|
||
wx.reportPerformance(1001, {
|
||
category: 'page_load',
|
||
name: 'entry_page',
|
||
value: Date.now() - startTime
|
||
})
|
||
|
||
// 游戏操作响应时间
|
||
this.trackUserInteraction()
|
||
}
|
||
|
||
// WebSocket连接质量监控
|
||
trackConnectionQuality() {
|
||
let pingStart = Date.now()
|
||
|
||
this.websocket.ping()
|
||
this.websocket.onPong(() => {
|
||
const latency = Date.now() - pingStart
|
||
wx.reportPerformance(1002, {
|
||
category: 'network',
|
||
name: 'websocket_latency',
|
||
value: latency
|
||
})
|
||
})
|
||
}
|
||
}
|
||
```
|
||
|
||
## 6. 开发计划和里程碑
|
||
|
||
### 6.1 开发阶段规划
|
||
```
|
||
第一阶段 (1周):
|
||
- 项目搭建 (2天)
|
||
- 基础UI开发 (5天)
|
||
|
||
第二阶段 (2周):
|
||
- 用户系统 (3天)
|
||
- 房间功能 (4天)
|
||
- 游戏核心逻辑 (6天)
|
||
- 实时通信 (3天)
|
||
|
||
第三阶段 (1周):
|
||
- 功能测试 (3天)
|
||
- 性能优化 (2天)
|
||
- 发布准备 (1天)
|
||
```
|
||
|
||
### 6.2 关键里程碑
|
||
- **Week 1**: 完成基础框架搭建和UI实现
|
||
- **Week 2**: 实现房间管理和游戏核心逻辑
|
||
- **Week 3**: 完成实时对战功能和测试优化
|
||
- **Week 4**: 发布上线和后续迭代
|
||
|
||
## 7. 风险评估和应对策略
|
||
|
||
### 7.1 技术风险
|
||
| 风险项 | 影响程度 | 应对策略 |
|
||
|-------|---------|----------|
|
||
| WebSocket连接稳定性 | 高 | 实现自动重连+离线缓存 |
|
||
| 小程序包体积限制 | 中 | 代码分包+资源CDN |
|
||
| 游戏状态同步复杂度 | 高 | 状态机设计+冲突解决 |
|
||
|
||
### 7.2 用户体验风险
|
||
| 风险项 | 影响程度 | 应对策略 |
|
||
|-------|---------|----------|
|
||
| 网络延迟影响体验 | 中 | 乐观更新+加载动画 |
|
||
| 不同设备适配问题 | 中 | 响应式设计+设备测试 |
|
||
| 游戏规则理解困难 | 低 | 新手引导+操作提示 |
|
||
|
||
## 8. 总结
|
||
|
||
本设计文档基于提供的原型设计,严格遵循MVP原则,提出了一套完整的微信小程序技术解决方案:
|
||
|
||
**核心优势**:
|
||
- 与原型设计高度一致的技术选型
|
||
- 现代化的前端架构和深色科技主题UI
|
||
- 高性能的实时对战体验
|
||
- 完善的错误处理和监控机制
|
||
- 清晰的开发计划和风险控制
|
||
|
||
**实现要点**:
|
||
- 使用Taro + React实现跨端能力
|
||
- Node.js + WebSocket保证实时性能
|
||
- MongoDB + Redis提供数据支撑
|
||
- 完整的状态管理和错误处理
|
||
|
||
本方案将为您的打飞机小程序提供坚实的技术基础,确保项目按时高质量交付。
|
||
|
||
---
|
||
**文档状态**: ✅ 完成
|
||
**技术评审**: 待进行
|
||
**下一步**: 开始技术选型实施 |