成就系统的难点在“刚刚发生”
成就页面本身不难:分类、进度、奖励、已完成。难的是玩家刚完成一个成就时,客户端如何及时、克制、准确地表现出来。战斗中弹一个大横幅会挡技能,剧情中弹出会破坏氛围,离线累计后一次弹十个又会像广告。
成就系统应该分成两部分:长期进度展示和即时反馈队列。长期进度负责页面、筛选、领取;即时反馈负责弹窗、音效、角标和节奏。两者共享同一份成就快照,但表现策略不同。
sequenceDiagram
participant Logic as 玩法逻辑/服务端推送
participant Model as 成就进度模型
participant Queue as 反馈队列
participant UI as 弹窗与页面
Logic->>Model: 进度变化或完成事件
Model->>Queue: 生成可展示事件
Queue->>UI: 按场景节奏弹出
UI->>Model: 玩家领取奖励
Model-->>UI: 刷新进度和红点
进度事件要去重
很多成就会频繁变化,例如击杀 100 只怪、累计移动距离、强化 10 次装备。客户端如果每次进度变化都刷新页面和上报动画,会浪费性能。进度模型应做节流:页面打开时可以实时更新,页面关闭时只记录最新值;只有跨过关键阈值或完成时才进入反馈队列。
完成事件也要去重。弱网重连后服务端可能补推已完成成就,客户端缓存里也可能已有完成状态。反馈队列要根据成就 ID 和完成版本判断是否已经展示过。否则玩家会反复看到同一个成就弹窗。
对隐藏成就要更谨慎。它们完成前不应暴露名称和条件,完成时才展示。客户端配置里可以存在隐藏标题的占位,但不要在日志和调试浮层里泄漏给普通玩家。
弹窗不是越多越好
成就弹窗的价值在于告诉玩家“刚才做的事被认可了”。如果每一分钟弹好几次,玩家会直接忽略。队列应按场景控制:战斗中延后到安全窗口,剧情中延后到剧情结束,结算页可以合并展示,主城闲置时可以即时弹。
弹窗大小也要克制。小成就用短条提示,稀有成就可用更强动效,白金或赛季成就可以进入结算展示。所有成就都用同一套大特效,不仅打扰玩家,也会让稀有成就失去层级。
队列还要有上限。一次离线回归完成 18 个成就,可以先展示 3 个代表性弹窗,再提供“还有 15 个成就已完成”的入口。玩家点进去看完整列表,比被迫看 18 次动画舒服得多。
页面筛选要帮玩家找目标
成就页面常见分类很多:成长、战斗、探索、社交、收集、限时、隐藏。单纯按分类排列会让玩家不知道下一步做什么。客户端可以提供几个实用筛选:即将完成、可领奖、稀有、未完成、已完成、最近更新。
“即将完成”很有用,但要小心计算成本。不要每帧计算所有成就进度百分比。进度模型更新时预先维护排序键,页面打开时直接使用。对于无法用百分比衡量的成就,比如“在不受伤的情况下通关”,可以由配置标记是否参与即将完成排序。
成就详情要显示条件、进度、奖励、跳转入口和限制说明。跳转入口不能硬连到某个玩法,应该走统一导航系统,处理模块未解锁、活动未开放、资源未下载等情况。
领奖和完成要解耦
成就完成不等于奖励已领取。很多项目在完成事件里直接发奖励,页面上又有领取按钮,最后状态混乱。建议成就状态分为:未完成、已完成待领取、已领取。服务端决定是否发奖,客户端只展示状态和发起领取。
如果设计要求自动发奖,也要让客户端把它表现成“已到账”,而不是继续显示领取按钮。两种模式不要混用在同一个成就类型里。运营临时改奖励策略时,客户端状态机要能明确兼容。
领取失败的处理和其他奖励系统类似:按钮锁定、请求、成功刷新、失败恢复。批量领取需要展示汇总结果,并且只刷新受影响成就,不重建整页。
红点要有层级
成就红点可能出现在主菜单、成就入口、分类页签、具体成就行。它们应该来自同一个红点树:只要某个成就待领取,分类和入口都有红点;如果只是进度更新但不可领取,不应该点亮主红点,可以用“最近更新”标记。
红点消失时机要清楚。玩家只是看到弹窗,不代表领取奖励;进入成就页面也不代表处理完成。只有领取成功或明确查看了某些“新完成但无奖励”的成就,红点才消失。否则玩家会错过奖励。
数据量和配置演进
成就数量会越来越多,配置也会跨版本演进。客户端要处理旧成就下线、新成就上线、条件文本变更、奖励变更和分类迁移。已完成的旧成就不能因为配置移动就丢失展示,至少要有兼容 ID 或历史页策略。
页面资源也要按需加载。成就徽章、稀有边框、分类图标可以缓存,但不要一次性加载所有高清图。列表虚拟化和图标懒加载同样适用。成就页面打开频率不算特别高,但一旦卡顿,会让玩家觉得系统很廉价。
小结
成就系统要表达认可,也要尊重玩家当前场景。客户端把进度模型、反馈队列、页面筛选、领奖事务和红点树拆开,成就就能从一堆条件列表变成有节奏的成长记录。它不是简单弹窗,而是玩家记忆的一部分。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
成就调试最需要的是事件回放能力:给定一组成就进度变化,客户端能复现弹窗队列、红点变化和页面排序。这样新增成就类型时,测试不必真的去刷一百次怪,也能检查反馈节奏是否正确。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。