# 对对碰(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) |