为什么值得单独做成系统
生存动作游戏里,玩家用铁斧砍树、格挡野兽攻击、在篝火旁修理装备。斧头耐久降到 15% 后攻击音效变钝,低于 5% 可能在下一次重击后损坏。耐久不是惩罚玩家,而是让资源循环有意义。
装备耐久系统很容易变成烦人的红条。要做得可信,损耗来源、修理成本、破损反馈、掉落经济和 UI 提示必须闭环。客户端要清楚展示状态,但不能让动画决定耐久变化。 本文会按一个可上线的小系统来拆,不追求炫技,而是把数据结构、状态流、玩家反馈、调试工具和发布检查说清楚。Phaser 的优势是让画面和交互快速成型,但越是快速,越需要把规则层和表现层分开。
核心架构
flowchart TD
N1["DurabilityEvent"] --> N2["WearRule"]
N2["WearRule"] --> N3["ItemInstance"]
N3["ItemInstance"] --> N4["BrokenState"]
N3["ItemInstance"] --> N5["RepairQuote"]
N5["RepairQuote"] --> N6["EconomySink"]
N4["BrokenState"] --> N7["InventoryUI"]
N7["InventoryUI"] --> N8["玩家决策"]
这张图的重点是单向流动。DurabilityEvent、ItemInstance、WearRule、RepairQuote、BrokenState、InventoryUI、EconomySink 不应该互相随意读写。输入或场景事件进入模型,模型输出快照或事件,Phaser 表现层再根据结果更新 Sprite、Graphics、Sound 和 UI。只要这条边界稳定,后续加内容、加难度、加存档或加多人同步,都不会把系统推倒重写。
耐久属于物品实例
同一种铁斧可以有不同耐久,所以耐久必须存到 ItemInstance,而不是 item config。配置里只写最大耐久、损耗规则和修理材料。实例里保存当前耐久、破损次数、是否绑定、最近修理时间。这样掉落、交易和存档都能准确表达单件装备。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
损耗事件要有来源
攻击、格挡、采集、死亡惩罚、环境腐蚀都可能降低耐久。DurabilityEvent 记录来源、强度、是否可被天赋减免。WearRule 根据装备类型计算实际损耗。不要在每个技能脚本里直接减 durability,否则平衡会散掉。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
破损不是突然消失
装备归零后可以进入 broken 状态:无法使用、属性下降、外观裂开或需要高级材料修复。直接删除装备会很挫败,除非项目本来就是硬核生存。BrokenState 要有明显反馈,但也要给玩家恢复路径。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
修理报价要透明
修理费用可以和损耗比例、装备稀有度、破损次数和地区折扣有关。RepairQuote 应显示所需金币、材料、成功率或耐久上限损失。玩家点击修理前就知道代价。若资源不足,提示缺什么,而不是按钮变灰无解释。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
耐久 UI 要分阶段提醒
100% 到 40% 不必打扰玩家,低于 30% 显示黄色,低于 10% 给音效或边框提示,破损时弹出明确结果。提醒太早会烦,太晚会像偷袭。不同装备槽位可以有汇总提示,避免背包里几十件物品都闪。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
经济闭环要防通胀
耐久是常见资源消耗点,但不能单独承担全部经济压力。修理费用要和收入曲线匹配,低级装备修理便宜,高级装备修理贵但可预期。若修理太贵,玩家会囤积不用;太便宜,系统没有意义。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
服务端权威项目要幂等
如果耐久影响交易或付费资源,损耗和修理要有 requestId。客户端可以预测耐久变化,但最终以权威结果为准。修理重复提交不能扣两次钱,损耗事件重复到达也不能减两次耐久。单机项目也可以保留事件 id,方便调试。
实现时建议先用最简单的调试图形验证规则,再接正式美术。比如先画出区域、方向、时间轴、占用格或检测范围,确认数据正确后再添加粒子、镜头、音效和过渡动画。这样做不花哨,但能避免很多“看起来对,规则其实错”的问题。
TypeScript 实现骨架
interface ItemInstance { id: string; configId: string; durability: number; maxDurability: number; broken: boolean }
interface DurabilityEvent { itemId: string; source: "attack" | "block" | "gather" | "death"; power: number; id: string }
function applyWear(item: ItemInstance, event: DurabilityEvent, multiplier = 1) {
if (item.broken) return item;
const loss = event.power * multiplier;
item.durability = Math.max(0, item.durability - loss);
if (item.durability <= 0) item.broken = true;
return item;
}
function repairQuote(item: ItemInstance, rarity: number) {
const missing = item.maxDurability - item.durability;
return { gold: Math.ceil(missing * (1 + rarity * 0.4)), materials: item.broken ? 2 : 1 };
}
function repair(item: ItemInstance) {
item.durability = item.maxDurability;
item.broken = false;
}
这段代码只展示核心边界,不是完整项目代码。真实项目里还需要补配置加载、错误码、事件派发、对象池、性能采样和测试。关键是让核心规则能独立运行,Phaser 层只是把规则结果变成玩家能感知的反馈。
落地步骤
- 第一,先把 DurabilityEvent 和 ItemInstance 写成普通 TypeScript 模型。不要让它们依赖 Phaser Scene、Sprite 或 Camera。核心模型越普通,越容易写测试、做编辑器预览和复现玩家问题。
- 第二,Phaser 层只做适配:接收输入、播放动画、更新图形、触发音效。它可以很薄,但必须清楚。只要某段规则开始读取 Sprite 的 visible、alpha 或动画状态,就说明边界正在变脏。
- 第三,给 WearRule 或同等复杂的中间结果做调试显示。开发模式里能看到状态、阈值、候选对象、失败原因和耗时,后续调参才不会靠猜。
- 第四,准备三组测试夹具:正常流程、边界流程、错误配置。正常流程验证体验,边界流程验证稳定性,错误配置验证系统会报出人能看懂的问题。
检查清单
- 确认 DurabilityEvent 的状态可以序列化,能写入存档或调试日志。
- 确认 ItemInstance 的配置有默认值、版本号和校验错误。
- 确认快速点击、暂停、切后台、读档和切场景不会重复提交关键事件。
- 确认失败反馈足够具体,玩家能知道是条件不足、输入中断、资源不够还是规则禁止。
- 确认低端机有降级策略,尤其是粒子、音效、动态对象和调试图层。
- 确认开发模式可以导出最近关键事件,方便复现玩家反馈。
常见误区
第一类误区,是把表现当成事实。动画播完、按钮亮着、Sprite 存在,都只能说明表现层当前长什么样,不能说明规则已经完成。规则事实应该存在于模型和事件里。
第二类误区,是只为了第一个关卡写逻辑。第一个关卡对象少、输入慢、节奏简单,临时判断很难暴露问题。等内容增加,重复触发、配置错误和性能峰值会一起出现,早期的边界会决定后期成本。
第三类误区,是没有设计失败路径。复杂系统一定会遇到失败,好的失败路径会告诉玩家和开发者发生了什么;坏的失败路径只会留下一句操作失败,甚至什么都不显示。
发布前验证
发布前至少跑一次规则级测试和一次运行时冒烟。规则级测试不需要启动浏览器,直接喂数据,断言状态和事件。运行时冒烟则在 Phaser 场景里验证输入、反馈、暂停、重开和边界情况。若系统涉及经济、存档或排行榜,还要记录 requestId 或事件 id,保证重复提交不会造成重复奖励或重复扣费。
额外实践建议
- 耐久变化要集中处理,不要散在技能脚本里。
- 修理费用要能在经济表里批量模拟。
- 低耐久反馈要分阶段,避免玩家被频繁打扰。
运行时观测与调参
耐久系统要和经济一起看。记录每种装备的平均损耗速度、玩家修理频率、破损后继续使用的比例、修理费用占收入比例,以及玩家是否因为耐久过低而中断任务。若修理太频繁,玩家会觉得被打断;若几乎没人修理,系统可能没有存在感。还要观察不同来源的损耗占比,例如格挡是否比攻击消耗过高,死亡惩罚是否让新手雪上加霜。调参时不要只改最大耐久,修理价格、材料掉落、低耐久提醒和破损惩罚都属于同一条循环。
耐久还会影响玩家对装备价值的判断。稀有装备如果修理太贵,玩家可能舍不得使用;普通装备如果太耐用,制作和掉落会失去意义。可以按装备等级统计“获得到首次修理”的时间,以及“破损后是否被替换”。这两个指标能帮助判断耐久是在制造选择,还是单纯增加负担。
如果游戏有自动修理或营地修理,也要把它们纳入同一条报价流程。自动修理只是少一步确认,不应该绕过材料、折扣、耐久上限和破损次数。否则玩家会发现手动修理和自动修理结果不同,经济系统的可信度会被迅速消耗。
这个差异必须被测试覆盖。
结语
装备耐久系统:损耗、修理、破损反馈和经济闭环 的关键不是某个 API,而是把可解释的规则交给模型,把可感知的反馈交给 Phaser。只要这条线清楚,项目就能持续扩展;如果所有逻辑都塞进 Scene 回调,第一版越快,后面的维护压力越大。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。