refactor: 重构抽奖逻辑以支持可验证凭据 feat(redis): 集成Redis客户端并添加配置支持 fix: 修复订单取消时的优惠券和库存处理逻辑 docs: 添加对对碰游戏前端对接指南和示例JSON test: 添加对对碰游戏模拟测试和验证逻辑
4.6 KiB
4.6 KiB
对对碰(Matching Game)前端对接指南
1. 核心流程概述
本版本采用 "预计算 + 客户端渲染" 模式,以确保流畅体验并防止网络延迟影响游戏节奏。
交互时序
- 开始游戏 (API): 用户点击开始 -> 调用
PreOrder接口 -> 服务器扣费并返回完整游戏剧本。 - 动画播放 (Frontend): 前端根据返回的
timeline数据,按顺序播放每一轮的 消除、填补、重洗 动画。 - 游戏结算 (API): 动画播放完毕(或用户点击跳过) -> 调用
Check接口 -> 服务器确认结束并发放奖励。
2. 接口调用详解
2.1 第一步:下单并获取数据 (Start)
- 接口:
POST /api/app/matching/preorder - 参数:
{ "issue_id": 123 } - 核心响应:
{ "game_id": "MG_123456", // 保存此ID用于结算 "initial_board": [ ... ], // 初始9宫格数据 (用于渲染第一帧) "timeline": [ ... ], // 关键!动画剧本数组 "total_pairs": 5 // 预计总消除对数 (可用于显示"目标") }
2.2 第二步:前端渲染循环 (Render)
前端拿到 timeline 后,不需要再请求服务器,直接在本地执行以下逻辑:
// 伪代码示例
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) |