1. 概述
本引导系统采用**递增序号(1, 2, 3, 4, 5)**管理用户的新手引导进度, 与服务端 AdvanceGuideStep 的"严格递增"语义天然契合。
2. 核心设计原则
2.1. 引导与领养分离
- 真正的引导:仅包含主页操作引导(喂食、收蛋、兑奖、赚鹅粮、碰一碰)
- 领养流程:选鹅、取名、领养成功属于首次领养流程,由
PetService.getFirstPet()判定 - 边界清晰:没有宠物时弹 AdoptPage,有宠物但
guide_step < STEP_LAST时弹 GuidePage
2.2. 递增序号机制
- 单调递增:每完成一步,
guide_step增加到对应步骤号 - 顺序固定:引导必须按 STEP_ORDER 顺序完成
- 服务端友好:服务端只要校验
新step > 旧step即可
3. 引导步骤定义
typescript
export const STEP_NONE = 0; // 未开始
export const STEP_FEED = 1; // 喂食引导
export const STEP_COLLECT = 2; // 收蛋引导
export const STEP_CLAIM_PRIZE = 3; // 兑奖
export const STEP_EARN_FOOD = 4; // 赚鹅粮引导
export const STEP_TAP = 5; // 碰一碰
export const STEP_LAST = STEP_TAP; // guide_step >= STEP_LAST 视为全部完成
export const STEP_ORDER: readonly number[] = [
STEP_FEED,
STEP_COLLECT,
STEP_CLAIM_PRIZE,
STEP_EARN_FOOD,
STEP_TAP,
];4. 辅助函数
typescript
/** 某个 step 是否已完成(已走过/到达) */
export function isStepDone(current: number, step: number): boolean {
return current >= step;
}
/** 找出第一个未完成的 step;全部完成返回 null */
export function nextPendingStep(current: number): number | null {
for (const s of STEP_ORDER) {
if (s > current) return s;
}
return null;
}
/** 是否全部引导步骤都已完成 */
export function isAllFinished(current: number): boolean {
return current >= STEP_LAST;
}5. 数据流
PlayerService.getGuideStep() ← 服务端 guide_step(当前进度序号)
↓
nextPendingStep(current) ← 找下一个 step > current 的步骤
↓
渲染该 step 的卡片
↓
用户点"知道了"
↓
advanceGuideStep({ step: cur }) ← 上报当前 step 作为新进度
PlayerService.reload() ← 拉取最新 guide_step
↓
循环找下一个 / 全部完成则关闭6. API 契约
6.1. advanceGuideStep
- 入参:
{ step: number }— 完成本步后期望的新进度序号 - 服务端校验:
step > 当前 guide_step,否则报错 - 返回:
{ guide_step: number }
6.2. Mock 实现策略
mock 端用 Math.max(old, step) 合并,确保进度只能前进不能回退,与服务端"严格递增"语义一致。
7. 典型场景
7.1. 场景 1:用户从 0 开始
guide_step = 0 → nextPendingStep → STEP_FEED(1) → 展示喂食引导
点"知道了" → advanceGuideStep(1) → guide_step = 1
guide_step = 1 → nextPendingStep → STEP_COLLECT(2) → 展示收蛋引导
...依次推进7.2. 场景 2:用户中途退出后再进入
guide_step = 2(已完成喂食、收蛋)
nextPendingStep(2) → STEP_CLAIM_PRIZE(3) → 直接从兑奖开始7.3. 场景 3:全部完成
guide_step = 5 → isAllFinished(5) === true → 不再展示引导8. 调试技巧
8.1. 强制从指定步骤开始
typescript
oops.gui.open(UIID.Guide, { startStep: STEP_CLAIM_PRIZE });8.2. 临时调整 mock 起点
修改 assets/scripts/api/data/player.ts 中的 mockState.guideStep 初值(如 3 = 从兑奖开始)。
8.3. 重置 mock 进度
typescript
import { resetMockGuideStep } from 'src/api/data/player';
resetMockGuideStep(0);9. 扩展性
9.1. 新增引导步骤
- 在
GuideConfig.ts末尾追加新常量(如export const STEP_SHARE = 6) - 把它加到
STEP_ORDER数组末尾 - 更新
STEP_LAST = STEP_SHARE - 在
STEP_META中补充对应的文案
9.2. 调整引导顺序
直接调整 STEP_ORDER 数组顺序即可,但需要注意:
- 由于服务端
guide_step是单调递增的序号,调整顺序后已完成用户的状态会发生语义偏移 - 推荐做法:保持现有 step 序号不变,新需求叠加在末尾
10. 最佳实践
10.1. 无魔法数字
- 业务代码只引用导出的常量与 helper
- 禁止硬编码
1/2/3等数字
10.2. 错误处理
advanceGuideStep失败时不阻塞 UI 推进- 用本地
currentStep兜底,让用户能正常走完流程
10.3. 状态同步
- 推进后调用
PlayerService.reload()拿最新进度 - reload 失败时用
Math.max(local, server)兜底,避免回退
11. 总结
本引导系统通过递增序号机制实现了灵活、可扩展的引导进度管理,支持:
- 多步骤并行完成
- 独立的状态标记
- 灵活的查询和推进
- 良好的服务端兼容性
- 易于扩展和维护
12. 掩码机制的核心优势
12.1. 步骤独立性
- 每个步骤可以独立完成,不受顺序限制
- 用户可以先完成"收蛋"(2),再完成"喂食"(1)
- 服务端只需要记录完成状态,不需要关心完成顺序
12.2. 灵活的状态查询
typescript
// 快速判断特定步骤是否完成
const hasFeed = (guideStep & STEP_FEED) === STEP_FEED;
const hasCollect = (guideStep & STEP_COLLECT) === STEP_COLLECT;
// 判断是否全部完成
const allFinished = (guideStep & STEP_ALL) === STEP_ALL;12.3. 服务端兼容性强
- 位掩码模式:服务端使用
guide_step |= step操作 - 严格递增模式:前端可以一次性提交
STEP_ALL兼容旧版本
12.4. 易于扩展
- 新增步骤只需添加新的2的幂次方常量
- 不影响现有步骤的完成状态
13. 关于30这个值的分析
13.1. 二进制分解
30的二进制: 11110
分解为: 16 + 8 + 4 + 2 = 3013.2. 步骤完成状态
- ✅ STEP_TAP(16) - 已完成
- ✅ STEP_EARN_FOOD(8) - 已完成
- ✅ STEP_CLAIM_PRIZE(4) - 已完成
- ✅ STEP_COLLECT(2) - 已完成
- ❌ STEP_FEED(1) - 未完成
13.3. 引导起点推断
typescript
// nextPendingStep(30) 的逻辑
STEP_ORDER = [1, 2, 4, 8, 16] // 按顺序检查
// 检查STEP_FEED(1): (30 & 1) === 1? false → 返回STEP_FEED结论:后台返回30确实会落到第一步(STEP_FEED),这是完全符合预期的!
14. 这种设计的业务意义
14.1. 支持用户跳过步骤
- 用户可能因为各种原因跳过某些引导
- 系统能够智能地从第一个未完成的步骤继续
14.2. 乱序完成的容错性
- 即使步骤完成顺序与设计不一致,系统也能正确处理
- 确保用户不会错过任何必要的引导
14.3. 调试和测试友好
- 可以通过设置不同的掩码值来测试各种场景
- 比如设置30来测试"只剩喂食未完成"的情况
15. 实际应用场景
15.1. 场景1:用户跳过喂食直接收蛋
初始状态: 0 (未开始)
用户完成收蛋: 0 | 2 = 2
下次引导: nextPendingStep(2) → 返回STEP_FEED(1)15.2. 场景2:用户完成除第一步外的所有步骤
状态: 30 (16+8+4+2)
下次引导: nextPendingStep(30) → 返回STEP_FEED(1)掩码机制的核心价值在于它的灵活性和鲁棒性,能够适应各种用户行为模式,确保引导系统既不会重复展示已完成的步骤,也不会遗漏未完成的步骤。