放置游戏离线收益:公式设计与实现
从玩家反馈说起
“我昨天晚上攒了100万金币去睡觉,结果今天早上只收到了1万金币,是不是BUG?”
这是上周收到的玩家反馈。排查后发现,问题不在代码,而在我们的离线收益公式设计——收益曲线太平缓,玩家离线8小时和离线1小时的收益差距只有2倍,完全没有“离线时间越长收益越高”的正反馈。
公式藏在Rate里
先看基础实现(internal/idle/idle.go 第114-121行):
1 | // 计算离线收益 |
表面看很简单:earned = Rate × elapsed。但关键在Rate的计算(第336-345行):
1 | func (s *Store) calcRate(upgrades map[string]int, prestigeMult float64) float64 { |
展开完整公式:
1 | earned = (baseRate × prestigeMult × Π effectMult_i^level_i) × elapsed_seconds |
其中baseRate = 1.0,所以:
1 | earned = (1.0 × prestigeMult × Π effectMult_i^level_i) × elapsed_seconds |
为什么用指数而不是线性? 线性增长会让玩家觉得“升级没什么用”,而指数增长会创造“指数爆炸”的爽感——等级越高,每级提升越明显。
三个升级怎么选
升级定义:成本与效果的平衡
1 | type UpgradeDef struct { |
三个升级的区别:
- click:点击收益,指数2.0,便宜但上限低
- generator:自动产出,指数1.5,中等成本
- speed:速度加成,指数1.3,最贵但效果稳定
购买逻辑:价格曲线
购买时的价格计算(第179行):
1 | cost := def.BaseCost * math.Pow(def.CostMult, float64(currentLevel)) |
举例:click升级
- Lv0→1:10 × 1.5⁰ = 10
- Lv1→2:10 × 1.5¹ = 15
- Lv2→3:10 × 1.5² = 22.5
前期便宜让玩家快速体验,后期昂贵制造稀缺性。
数值验证:测试用例
测试文件(idle_test.go 第392-418行)展示了组合效果:
| 场景 | 输入 | 期望速率 |
|---|---|---|
| 无升级 | {}, ×1.0 |
1.0 |
| click lv1 | click:1, ×1.0 | 2.0 (1×2¹) |
| click lv2 | click:2, ×1.0 | 4.0 (1×2²) |
| generator lv1 | generator:1, ×1.0 | 1.5 (1×1.5¹) |
| 重生加成 | {}, ×1.5 |
1.5 |
| 组合 | click:1+generator:1, ×2.0 | 6.0 (2×2×1.5) |
升级组合是乘法关系,不是加法!这意味着策略性——玩家需要选择升级哪个属性。
重生按钮:重置还是保留
为什么是1000
1 | if state.Resources < 1000 { // 至少持有 1000 资源 |
为什么是1000? 这个数字需要让玩家:
- 有足够的投入感(至少玩了几小时)
- 又不至于太长(让玩家有频繁重生的可能)
重生加成公式
1 | state.PrestigeLevel++ |
这里选择线性(+0.5/次),而不是指数。原因:
- 指数增长会让早期重生收益过高,玩家会不断重置,失去游戏节奏
- 线性增长保持稳定预期,玩家知道每次重生固定提升50%
- 配合升级系统的指数增长,形成“永久线性 + 临时指数”的双层结构
清零什么保留什么
1 | state.Resources = 0 // 资源清零 |
只保留prestigeLevel和prestigeMult。这是核心设计:
- 清零升级:让玩家重新体验升级快感
- 保留倍率:让每次重生都有实际收益
- 重算速率:确保重生后立即感受到提升
客户端怎么显示重生结果
Godot客户端的重生反馈(demo-godot/scripts/idle.gd 第34-43行):
1 | func _on_prestige_pressed(): |
立即显示新倍率和重置后的速率。玩家能直观感受到“重生后产出从1.0/秒变成1.5/秒”。
防崩设计
资源通胀控制
- 升级成本指数增长(CostMult > 1.0)
- 产出指数增长(EffectMult > 1.0)
- 但产出指数 < 成本指数,确保不会无限通胀
重生频率控制
- 阈值1000确保至少玩1-2小时
- 线性倍率避免频繁重置的诱惑
- 最大等级限制防止数值爆炸
离线收益上限
虽然代码中没有明确的上限,但实际通过以下方式控制:
- 离线时间越长,收益边际效益递减
- 升级需要在线操作,离线只是积累资源
- 重生需要手动操作,不能自动
一个玩家的例子
玩家A的升级路径:
1 | Day 1: click:10, generator:5 → 产出 2.0×1.5^5 ≈ 15.2/秒 |
观察:每次重生提升50%,但升级的指数增长才是主要收益来源。重生是“锦上添花”,不是“雪中送炭”。
新问题
放置游戏的核心是“让玩家感觉时间在为自己工作”。离线收益公式的设计,本质上是在回答一个问题:如何用最小的代码量,创造最强烈的正反馈?
我们的答案是:指数增长的升级 + 线性增长的永久加成 + 1000资源的重生门槛。这套组合拳让玩家有持续的目标感,又不会陷入数值膨胀的陷阱。
但有个隐患:重生次数多了以后,50 倍的线性加成会让游戏失去挑战。我们目前还没处理这个问题,玩家反馈也暂时没提到。可能等 DAU 再上一个量级时,得加个倍率衰减或者重生上限。