拼棋派对开发实战系列封面

翻开两张牌,记住图片的位置,下一轮争取找到配对。双人记忆挑战的难点不是图片显示,而是时间与状态:两张不相同的牌需要短暂保留,期间不能翻第三张;重开以后,上一局的延迟回调也不能把新牌盖回去。

《拼棋派对》使用12张牌、6组图片,配对成功得1分并继续翻牌,失败回盖后换人。本文在HarmonyOS7 API26手机模拟器中走完配对与结算,分析锁定标志和回合代数怎样配合。示例为主应用1.0.19。

本文目录

牌的身份与显示状态

createMemoryCards 为山湖、城市、星际、美食、音乐、竞速六组主题各生成两张牌,再按seed打乱。两张配对牌的id不同,value相同。图片资源是展示内容,value才是配对依据。

字段或状态表达的含义
id某一张牌的稳定身份
value所属图片组,比较相等时配对
flipped本回合已经翻开
matched已经成功配对,保持公开
memoryFirstIndex第一张待比较牌的位置
memoryLocked两张失败牌等待回盖,禁止继续翻牌
memoryCurrent当前行动玩家A或B

如果把value直接作为列表唯一键,一对牌就会共享键,列表更新可能混淆。页面应该使用牌的id表达身份,用value比较组别。配对后matched保持true,避免已经得分的牌再次参与计算。

每次修改牌状态,项目用 cloneMemoryCards 克隆对象。只复制数组却继续修改数组里的同一对象,仍然会影响旧数据;克隆牌对象让前后状态的归属更清楚。

第一张和第二张分别处理

点击入口先拒绝锁定、比赛结束、越界、已配对或已翻开的牌。第一张只修改flipped与memoryFirstIndex,不增加回合数。第二张才构成一次尝试,回合数加一,比较两张value。

成功分支的核心代码如下,省略音效和提示:

if (cards[this.memoryFirstIndex].value === cards[index].value) {
  cards[this.memoryFirstIndex].matched = true;
  cards[index].matched = true;
  this.memoryMatched += 1;
  if (this.memoryCurrent === 'A') {
    this.memoryScoreA += 1;
  } else {
    this.memoryScoreB += 1;
  }
  this.memoryCards = cards;
  this.memoryFirstIndex = -1;
  if (this.memoryMatched >= 6) {
    this.finishMemoryFlip();
  }
  return;
}

成功后没有切换memoryCurrent,因此同一玩家继续翻下一组。只清理第一张索引,让下一次点击重新从“本回合第一张”开始。不要把清除索引与换人绑定在一个公共函数里,否则会改变玩法规则。

失败后锁住输入

不匹配时两张牌保持翻开720毫秒,让玩家有时间记住位置。设置memoryLocked以后,任何额外点击只给等待提示,不改变盘面。这可以防止第三张牌混进当前比较。

延迟回调需要保存firstIndex、secondIndex和currentPlayer,而不是在执行时读取可能已经变化的选择状态。回盖时克隆当前牌数组,只回盖仍未matched的对应牌,再解除锁定并切换玩家。

this.memoryLocked = true;
setTimeout(() => {
  if (roundEpoch !== this.memoryRoundEpoch || this.memoryFinished) {
    return;
  }
  const nextCards = this.cloneMemoryCards(this.memoryCards);
  if (firstIndex >= 0 && firstIndex < nextCards.length &&
      !nextCards[firstIndex].matched) {
    nextCards[firstIndex].flipped = false;
  }
  if (secondIndex >= 0 && secondIndex < nextCards.length &&
      !nextCards[secondIndex].matched) {
    nextCards[secondIndex].flipped = false;
  }
  this.memoryCards = nextCards;
  this.memoryLocked = false;
  this.memoryCurrent = currentPlayer === 'A' ? 'B' : 'A';
}, 720);

代码节选保留了回调的主要保护条件。720毫秒是交互等待时间,不是答题倒计时,也不是帧率控制。

让旧回调失效

用户可能在两张失败牌尚未回盖时点击重开。新局已经重新发牌,如果旧定时器继续执行,就会改动新局同样索引处的牌,并把行动方切成上一局的对手。

项目使用memoryRoundEpoch标识当前有效回调。创建失败回调时增加代数并保存局部值;重开时再次增加代数。回调执行前发现局部值与当前值不同,就返回。

这个方式不依赖旧索引是否仍然有效。旧索引合法,也可能属于完全不同的新局;代数检查的是操作属于哪一次有效状态。提示高亮另外使用memoryHintEpoch,避免多个提示回调互相覆盖。

重开统一清空分数、回合、配对数、用时、第一张索引、提示列表、锁定与结束标志,并让A先翻。只重新生成cards而保留memoryLocked,会让新局看起来完整却无法操作。

提示、结算与重开

提示从未配对牌里找一组相同value,短暂标出两个位置,950毫秒后清除提示列表。它不直接计分,也不把牌标为matched。提示与真正配对走不同状态路径。

全部6组配完后,停止对局、计算胜者并记录双方比分、回合数与用时。两人分数相同为平局。成功继续行动、失败才换人的规则意味着一名玩家可能连拿多分,不能期待每两张牌就固定换人。

实际翻牌效果

进入“反应记忆→双人记忆挑战”,重开后观察12张背面牌。实操先逐张翻开记住图案,再按可见图片配对,走到六组完成和结果显示;随后重开检查双方分数恢复0。

记忆挑战翻开图片,完成六组配对、结算并重开

动图中应同时观察三件事:翻开第二张后是否配对、成功配对数是否增加、当前玩家是否符合成功继续和失败换人的规则。仅检查图片出现,无法证明回合控制正确。

本轮完成了可见图片配对与结算取证。720毫秒锁定窗口中的第三次点击、回盖前重开和多次提示的回调竞争,仍需要专门的快速操作用例。本文解释其保护代码,不把正常配对过程当作这些边界都已验证。

源码入口:common/GameLogic.ets 的 createMemoryCards;pages/Index.ets 的 handleMemoryTap、memoryHint、restartMemoryFlip 和 finishMemoryFlip。参考HarmonyOS官方文档。下一篇分析反应抢点的亮点切换与得分入口。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐