跳到主要内容

游戏状态:让重开、暂停和结算有边界

功能越多,“现在到底能不能操作”越难靠零散布尔值解释。isPlaying、isPaused、isOver 如果可以同时为真,排错会越来越痛苦。

把合法状态先列出来​

每个状态定义可以做什么,而不是只定义显示哪个界面。

状态允许输入时间显示
Ready开始、设置不推进开始提示
Playing玩法操作、暂停推进游戏与 HUD
Paused恢复、退出不推进暂停面板
Settled重开、返回不推进结果与奖励状态

入门脚本只实现 Playing 和 Settled。增加暂停时,要同时处理时间、输入、音频与异步结果;仅把暂停面板显示出来并不等于游戏已经暂停。

一个转换入口比到处改值更清楚​

type Phase = 'ready' | 'playing' | 'paused' | 'settled';
let phase: Phase = 'ready';

function finish(): boolean {
if (phase !== 'playing') return false;
phase = 'settled';
return true; // 调用者仅在 true 时发起本局结算
}

这段是规则片段,不是可直接挂载的组件。重点在于:转换前检查来源状态,转换后只做一次对应副作用。

异步结果也有“属于哪一局”的问题​

玩家提交结算后立刻重开,上一局请求稍后返回。如果回调直接改当前 UI,新的游戏就会显示旧结果。可以给每局一个递增 roundId:发起时捕获它,回调回来后比较是否仍是本局,再决定展示。

服务端结算使用独立的幂等标识,不能因为客户端忽略旧 UI 回调,就认为服务端重复奖励问题也解决了。

验收与 AI 对话​

请先画出准备、游玩、暂停、结算的状态图。
列出每个状态允许的按钮、计时行为与异步回调处理。
重开会产生新的 roundId;旧局结果不能覆盖当前 UI。
测试:重复点击结算、暂停时点目标、结算请求中重开。

暂停策略、状态优先级和重开是否保留进度,都是玩法需求。不要让 AI 在写代码过程中悄悄决定。

依据:Creator 生命周期;状态划分与 roundId 是本文的应用设计建议。