跳到主要内容

规则、状态与表现分离

级别:首作必学。 游戏状态描述现在成立的事实,规则描述输入如何改变这些事实,表现负责让玩家感知变化。把它们分开后,动画可以替换,规则仍可独立检查。

翻牌配对的不变量​

  • 每张牌有稳定 ID,牌面相同的牌形成一对。
  • 配对完成的牌不能再次翻开。
  • 第一张和第二张必须是不同的牌。
  • 不匹配的两张展示期间,拒绝第三次翻牌。
  • 每翻开第二张消耗一回合。
  • 最后一回合如果完成全部配对,结果是胜利。
  • 胜负确定后,后续翻牌不再改变状态。

这相当于你熟悉的领域约束。不要让某个 UI 按钮是否禁用成为唯一保护;规则层也要拒绝非法输入。

最小状态机​

playing ─第一张→ playing
playing ─第二张相同→ playing / won / lost
playing ─第二张不同→ resolving ─展示结束→ playing / lost

应用暂停可以作为外层状态:foreground/background。它决定是否接收输入和推进表现,不必把所有组合都塞进一个巨大的枚举。

单向的数据流​

触摸 → flip(id) → 新规则状态 → render(state)
↓
动画、声音、计数与结算

卡牌文字、SpriteFrame 和按钮状态都是渲染结果。需要知道牌是否配对时,查询规则状态,而不是读取节点颜色。这样更容易在重开、恢复或调试时重建一致画面。

何时提交状态​

翻牌配对可以先提交规则,再播放表现。不匹配时规则进入 resolving,约定展示完成后显式调用 resolve。动画取消、切后台或场景退出,都必须定义这次判定如何结束。

动画完成回调不应直接写奖励余额;规则或专门结算函数决定是否允许结算。UI 只呈现结果,平台奖励需要进一步考虑可信边界。

不必先引入大型框架​

纯函数加一份明确状态,已能支撑教学项目。复杂状态库、全局事件总线、依赖注入和通用 ECS 都需要有清楚的收益才引入。先通过可读的函数边界组织代码。

练习:写出“不匹配时点第三张”的输入序列,并断言状态完全不变。再写“最后一回合恰好全部配对”的序列,确认胜利判断优先于回合耗尽。完整实现见翻牌规则模型。