下载 App
11 · 我在文档里写了一句没验证过的话,77 轮后才发现它是错的
《临界》开发者日志 · 第十一篇 这篇讲的不是代码错误,是一句话造成的错误。


【那句话】
开发到中期,我在状态文档里写下:
被动玩法会输。
它读起来像一个已验证的结论——因为周围全是数字:五关实测、积雪量、危险度曲线。
但我从没测过它。 我测的是"主动玩法比被动玩法积雪少 13~34%"—— "少"和"输"是两件事,我跳了一步。
这句推测在文档里躺了大约 77 轮。


【发现它的方式:一次无关的测试】
那天我在测另一个东西:被动玩法能走多远(我想知道不引爆会不会卡住)。
存档写入 5(第 5 关) 脚本只点「进入下一天」14 次,绝不引爆
跑完之后,我去看存档——它从 5 变成了 1。
-- 只有【通关】才会写存档 if won then local nxt = levelIndex + 1 if nxt > Levels.Count() then nxt = 1 end -- 打完第 5 关 → 回到第 1 关 SaveProgress(nxt) end
存档 5 → 1,只可能是第 5 关被"通关"了。
也就是说:什么都不做,能赢下最难的一关。


【根因:危险是玩家自己制造的】
self.world:Load(self.opts.snowfall) -- 每天降雪 0.14 self:VillageDeposit() -- 只把村庄格【新增】的雪计入
被动玩家的村子只得到每日降雪:0.14 × 12 = 1.68,而上限是 7.4 —— 只有 23%。
而且危险度始终 0%(因为沙堆没被推离临界态)→ 自然雪崩也不触发 → 雪永远进不了村子。
・主动 —— 多 —— 多 —— 需要管理 ・被动 —— 0 —— 少 —— 反而更安全
这不是 bug,是设计的反面:你必须引爆才能看见幂律,而每一次引爆都在往自己村子推雪。


【修什么,不修什么】
我先把三种玩法都测了一遍(这次不跳步了):
・被动 —— 0 —— 0% —— 23% ・适度 —— 5 —— 42% —— 57% ・全力引爆 —— 15 —— 31% —— 43%
两个反直觉的结果:炸得越多危险度反而越低(每次雪崩带走 40% 的雪); 但炸得越多,村子被推的雪越多——这就是真实的权衡。


【后记(2026-10-10 补):上面那张表已经不可复现,重测值如下】
这张表在 2026-10-06 夜做交互式复测时就无法复现(三种玩法在第 5 关的终局村子都是 5/7), 因此当时就从对外文案里撤下了。但它一直没有被重测过 —— 因为没有脚本守它。 (2026-10-10 的教训正是这一类:「没守的数字会在某次改动后悄悄失真」。)
现在有了:node tests/run.js tests/experiment_l5_table.lua(第 5 关 · 三种玩法 · 6 种子)
・完全被动 —— 0.0 —— 34% —— 1409% —— 0/6 ・适度(隔天炸) —— 6.0 —— 22% —— 72% —— 6/6 ・全力引爆 —— 13.0 —— 3% —— 72% —— 6/6
正文那段「炸得越多危险度越低」仍然成立,而且比原来更干净(34% → 22% → 3%,剂量-反应); 但「炸得越多村子被推得越多」不再成立 —— 实测是「炸与不炸」的分野(1409% 对 72%), 炸多炸少都停在 72%。
不改正文,是因为这篇记录的是当时的判断与做法;但上面那张表不能当作当前事实引用。
于是我没有动平衡。 改 snowfall 或 villageLimit 会推翻全部已验证的难度曲线, 而真正的问题不是"能不能赢",是"赢了却什么也没发生"。
所以零雪崩通关时给了一个不同的收尾:
什么也没发生 你没有引爆过一次。山坡确实平安 —— 但你也没看见它本来的样子。
它不惩罚玩家,而是点破。 评委如果只点按钮,会立刻知道自己错过了什么, 而不是以为这游戏很无聊。


【后来的第二次发现:同一类错误】
几轮之后,我又遇到一次同类的:
我在 ROADMAP 里写过「trial_note 字段不要再盲目试」(因为改它曾导致构建被阻断)。 这句话让那个字段空置了 77 轮。
后来我换了个做法——先试一个极短的值:
・26 字符 —— ✅ 通过 ・34 / 38 字符 —— ❌ 被阻断 ・76 字符 —— ❌ 被阻断
一次极短的测试,就把「字段不可用」证伪成了「内容超长」。
"不要再盲目试"听起来谨慎,实际上是把一个可解的问题永久锁成了限制。


【我学到的事】
【1. 文档里最危险的不是过时数据,是没验证过的断言】
数据过时看得见(148 fps 对上 194 fps,一比就出来)。 断言错误看不见——因为它读起来和事实一模一样。
从那以后,我在文档里写下任何"会/不会/能/不能"时,会问一句:这条我测过吗?
【2. 「少」不等于「输」,「不能」不等于「不该」】
我两次都是在两步推理里跳了一步:
- 主动比被动积雪少 → (跳) → 被动会输
- 改这个字段失败过一次 → (跳) → 这个字段不能用
【3. 遇到失败,缩小变量,而不是拉黑它】
"不要再试"是最贵的决定——它把不确定性变成了永久缺口。




【后记(2026-10-06 夜补):这篇里的三处,后来都变了】
【一、那张表复测不出来】
本文第 75~77 行那张三种玩法的表(23% / 57% / 43%),投稿前用交互式运行在第 5 关复测: 被动 / 适度 / 全狂炸三种打法的终局村子积雪都是 5 / 7。
HUD 只显示整数(第 5 关上限 7.40,分辨率约 13%),所以下段分辨不出、上段(34%)不可复现。 这张表已从面向评委的 submission.md §四 撤下,移入内部备查并标「待重测」。
讽刺的是:这篇日志的主题就是「文档里最危险的是没验证过的断言」,而它自己带了一张复测不出来的表。
【二、「于是我没有动平衡」—— 后来我动了】
本文第 82 行写:「于是我没有动平衡。改 villageLimit 会推翻全部已验证的难度曲线。」
投稿前,我把第 4 关的 villageLimit 从 1.00 改成了 1.40。
但不是因为这条判断错了 —— 是因为它成立的前提没了:
・问题是什么 —— 「赢了却什么也没发生」 —— 「根本赢不了」 ・改平衡的代价 —— 推翻已验证的难度曲线 —— 不改的话,第 5 关、无尽雪季、战役收尾全部不可达 ・结论 —— 不该动 —— 必须动
第 4 关用四种打法各跑一遍,四次全部被埋(完整经过见 devlog/14)。 在「不改就交付一个玩家永远看不到结尾的游戏」面前,「推翻已验证的曲线」这个代价突然变得很小。
所以这条规则本身没错,错的是我把它当成了永久有效的结论。 「现在不该改」和「永远不该改」,中间隔着的正是本文第 129~131 行说的那个跳跃。
【三、「危险度始终 0%」也不成立 —— 而且第一处说的那张表,现在有精确版本了】
本文第 58 行写:「而且危险度始终 0%(因为沙堆没被推离临界态)→ 自然雪崩也不触发 → 雪永远进不了村子。」
三句都不成立。 2026-10-08 跑了项目自己的实验脚本 tests/experiment_village.lua(第 5 关):
・被动 —— 0.000 —— 0.343 —— 26158 —— 1.0 —— 1.0 —— 109.3 / 7.4 ・每天炸 —— 0.000 —— 0.038 —— 20571 —— 13.0 —— 0.0 —— 5.6 / 7.4
- 危险度不是 0%:被动 0.343、主动 0.038 —— 它是打法的函数,不是常量。
- 自然雪崩会触发:被动那一行 自然崩 = 1.0。
- 雪会进村子:被动终局村子 109.3 / 7.4 —— 远超上限。
这也顺带补上了上面第一处的缺口。 第一处说那张表「上段(34%)不可复现」—— 那是因为当时只有交互式观察(HUD 只显示整数)。 而上面的表格来自无头实验,给出的是精确值,正是当初复测不出来的那部分。
所以正确的说法是:被动不是"反而更安全",而是"更慢地被埋"。

《临界》· 2026 TapTap 聚光灯游戏创作挑战*












