5 行代码让我的 Roguelike 每天都值得玩
It looks like only the source line was provided. Could you please share the full text you’d like translated? Once I have the content, I’ll translate it into Simplified Chinese while preserving the formatting, markdown, and any code blocks.
背景
- 在 v0.10.0 中,我给我的 roguelike 的每一次运行都起了名字。
- 在 v0.11.0 中,我把每一天都当作一次运行。
Endless Mode 的问题
当我发布 Endless Mode(v0.9.9)时,我在结果画面添加了这行文字:
“在 itch.io 评论区发布你的 Endless 成绩!”
我本以为玩家会自然而然地把评论区变成排行榜。
问题在于: 没有两个通关是相同的。当一位玩家发布 “我以 Chain Annihilator 生存到第 27 波” 时,其他玩家没有可供比较的对象。他们玩的是不同的地图,选择了不同的升级,面对的敌人模式也不同。
itch.io 的评论区并不是排行榜,它只是一串互不相关的成就列表。
什么让排行榜有效
A leaderboard needs a fixed variable.
- Golf: 球场是固定的。玩家在相同的 18 洞上竞争,因此比较是有效的,因为挑战是相同的。
- Wordle: 单词是固定的。每位玩家得到相同的谜题;唯一的变量是猜测次数。
- My roguelike: 没有任何固定的东西。每次运行都有随机种子,每次刷新也随机。
The fix was obvious once I saw it: use the date as the seed.
实现
每一次在 Spell Cascade 中的运行都会使用 Godot 的全局随机数生成器来:
- 敌人类型选择(
randi() % pool) - 敌人生成位置(
randf_range()) - 升级选项(
array.shuffle()) - 精英敌人概率(
randf())
下面的代码在加载游戏场景之前设置一个确定性的每日种子:
func _on_start_daily_challenge() -> void:
if _transitioning:
return
_transitioning = true
var date: Dictionary = Time.get_date_dict_from_system()
var seed_base: int = (int(date.year) * 10000) + (int(date.month) * 100) + int(date.day)
var daily_seed: int = seed_base * 31337 # prime number distribution
Engine.set_meta("daily_challenge_seed", daily_seed)
var scene: PackedScene = load("res://scenes/game.tscn")
get_tree().change_scene_to_packed(scene)游戏场景 – 加载时的种子设置 (game_main.gd)
# game_main.gd — seed setup on game load
func _ready() -> void:
if Engine.has_meta("daily_challenge_seed"):
var daily_seed: int = Engine.get_meta("daily_challenge_seed")
seed(daily_seed)
is_daily_challenge = true
Engine.remove_meta("daily_challenge_seed")seed() 调用会设置 Godot 全局 RNG 的状态。此后所有的 randi()、randf() 和 array.shuffle() 都会变得确定性。
使用 Engine‑metadata 的模式可以在 不使用 autoload 单例 的情况下处理标题到游戏场景的切换:在场景切换前设置值,加载时立即读取并删除它。
2026‑02‑21 的样子
On February 21, 2026, the seed is:
20260221 × 31337 = 634,601,577Every player who clicks “Daily Challenge 02/21” that day gets:
- 相同的前三个敌人
- 在2、3、4… 级时相同的升级选项
- 相同的精英敌人出现
- 相同的Boss触发时机
What differs is their reaction time, decision making, and skill execution. The “map” is shared; the score is earned.
社交机制
在发布后 24 小时内,第一条每日挑战帖子出现在 itch.io 评论中——不仅有得分,还有事后分析:
“作为链式歼灭者到达第 19 波。差点通关无限模式,但 8:30 的分裂波把我拦住了。”
这条帖子之所以重要,是因为其他玩家也经历了同样的 8:30 分裂波。他们可以直接比较,使用当天的共享参考点。
每日挑战的哲学
每日挑战解决了一个 社会协同问题。
没有共享种子,比较 roguelike 运行需要依赖统计相似性——“我们两人在平均上玩的是同样的难度”。这对竞争来说是一个薄弱的基础。
有共享种子,比较是直接的。“我们都在 8:30 看到了那个分割波”是一个事实,而不是近似。
每日挑战还提供了自然的回归理由:不是“我想变得更好”(模糊)而是“我还没有完成今天的挑战”(具体、可执行、会过期)。
AI 的贡献
这个想法来源于阅读 Wordle 如何驱动其参与循环的内容。实现上的问题——如何在 Godot 中设置确定性种子而不破坏普通模式——是我之前不知道的。
Claude Code 确认:
seed()设置全局状态,因此所有后续调用都会继承它。- Engine‑metadata 模式用于在场景之间传递数据,而无需单例。
起初这些对我来说并不明显。
我提供的内容: 我的评论区未能作为排行榜工作,以及共享种子可以解决该问题的理论。
Claude 的贡献: 使其工作起来的两行实现。
开放性问题:合适的每日重置时间
目前它在 本地午夜 重置。这意味着不同时区的玩家实际上在不同的时刻开始“不同的天”。
- 支持 UTC 午夜的理由: 单一的全局重置。
- 问题所在: UTC 午夜是日本标准时间上午 9 点——对日本玩家来说不太方便。
我还没有找到解决方案。目前采用 本地日期。如果玩家基数足够大,以至于时区不一致成为问题,那就真的需要处理了。
目前: 同一天,同一随机种子。如果你在玩 2 月 21 日的内容,那就是 2 月 21 日的轮次。
开始玩
Spell Cascade 在浏览器中免费使用:
你的 Claude Code 设置… (原文在此截断)。
你的代码真的安全吗?
运行 npx cc-health-check — 免费的 20 分诊断。
得分低于 80?Claude Code Ops Kit 可一键修复所有问题。
今天你达到了第几波?