bindbox-game/docs/前端对接指南_对对碰.md
邹方成 e2782a69d3 feat: 添加对对碰游戏功能与Redis支持
refactor: 重构抽奖逻辑以支持可验证凭据
feat(redis): 集成Redis客户端并添加配置支持
fix: 修复订单取消时的优惠券和库存处理逻辑
docs: 添加对对碰游戏前端对接指南和示例JSON
test: 添加对对碰游戏模拟测试和验证逻辑
2025-12-21 17:31:32 +08:00

123 lines
4.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 对对碰Matching Game前端对接指南
## 1. 核心流程概述
本版本采用 **"预计算 + 客户端渲染"** 模式,以确保流畅体验并防止网络延迟影响游戏节奏。
### 交互时序
1. **开始游戏 (API)**: 用户点击开始 -> 调用 `PreOrder` 接口 -> 服务器扣费并返回**完整游戏剧本**。
2. **动画播放 (Frontend)**: 前端根据返回的 `timeline` 数据,按顺序播放每一轮的 消除、填补、重洗 动画。
3. **游戏结算 (API)**: 动画播放完毕(或用户点击跳过) -> 调用 `Check` 接口 -> 服务器确认结束并发放奖励。
---
## 2. 接口调用详解
### 2.1 第一步:下单并获取数据 (Start)
* **接口**: `POST /api/app/matching/preorder`
* **参数**: `{ "issue_id": 123 }`
* **核心响应**:
```json
{
"game_id": "MG_123456", // 保存此ID用于结算
"initial_board": [ ... ], // 初始9宫格数据 (用于渲染第一帧)
"timeline": [ ... ], // 关键!动画剧本数组
"total_pairs": 5 // 预计总消除对数 (可用于显示"目标")
}
```
### 2.2 第二步:前端渲染循环 (Render)
前端拿到 `timeline` 后,不需要再请求服务器,直接在本地执行以下逻辑:
```javascript
// 伪代码示例
async function playFullGame(data) {
// 1. 渲染初始棋盘
renderBoard(data.initial_board);
// 2. 遍历时间轴,逐回合播放
for (const round of data.timeline) {
// --- 阶段 A: 消除动画 ---
if (round.pairs.length > 0) {
// 高亮要消除的卡牌
highlightCards(round.pairs);
await wait(500); // 停顿
// 播放消除特效(根据 slot_indices 找到对应格子)
for (const pair of round.pairs) {
// pair.slot_indices 数组包含了所有要消除的格子下标 (0-8)
playEliminateEffect(pair.slot_indices);
}
await wait(500); // 等待特效结束
// 从界面移除卡牌 DOM
removeCardsFromBoard(round.pairs);
}
// --- 阶段 B: 填补动画 ---
if (round.drawn_cards.length > 0) {
// 播放发牌/飞入动画
for (const draw of round.drawn_cards) {
// draw.slot_index 是目标格子
// draw.card 是新卡牌数据
flyCardToSlot(draw.card, draw.slot_index);
}
await wait(500);
}
// --- 阶段 C: 死局重洗 (如果有) ---
if (round.reshuffled) {
showToast("死局重洗中...");
playShuffleAnimation(); // 播放所有卡牌重新排列的动画
// 动画结束后,根据 round.board 更新整个棋盘状态,确保位置正确
updateFullBoard(round.board);
await wait(1000);
}
// 每一轮结束后稍作停顿
await wait(300);
}
// 3. 全部播放完毕,调用结算
doCheck(data.game_id);
}
```
### 2.3 第三步:结算与领奖 (Check)
* **接口**: `POST /api/app/matching/check`
* **参数**: `{ "game_id": "MG_123456" }`
* **作用**: 告知服务器动画已播完触发最终奖励发放虽然服务器在PreOrder时已经计算好了但这个调用作为完整的业务闭环
---
## 3. 数据结构字典
### `MatchingRoundResult` (时间轴中的每一项)
| 字段 | 类型 | 说明 | 前端处理建议 |
| :--- | :--- | :--- | :--- |
| `round` | int | 回合数 | 用于UI显示"第几轮" |
| `pairs` | array | 消除列表 | **关键**:遍历此数组,读取 `slot_indices` 来决定哪些格子要播消除动画 |
| `drawn_cards` | array | 填补列表 | **关键**:遍历此数组,读取 `slot_index` 来决定新卡牌飞入哪个格子 |
| `reshuffled` | bool | 是否重洗 | 若为 true必须播放全屏洗牌特效并强制刷新棋盘数据 |
| `can_continue` | bool | 是否继续 | 若为 false播放完本轮后显示"游戏结束"弹窗 |
### `MatchingPair` (消除详情)
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| `card_type` | string | 消除的卡牌类型 |
| `count` | int | 消除数量 (通常是2连消可能是4,6) |
| `slot_indices` | int[] | **核心**:被消除的格子下标列表,如 `[0, 1]` |
### `DrawnCardInfo` (填补详情)
| 字段 | 类型 | 说明 |
| :--- | :--- | :--- |
| `slot_index` | int | **核心**:填入的目标格子下标 (0-8) |
| `card` | object | 新卡牌的完整数据 (id, image_url, name) |