日期: 2026-10-14
当前进度: 补上缺失的外层循环(转生/道基);知识从二值开关升级为可深造、可组合、可跨局继承;修复一个 0.75% 概率的地图崩溃;首次打通本地预览验证
下载 App
《我真没让他们建城啊!》开发者日志 06
修改于10/1673 浏览综合
06 让那条链被看见了。
但玩家看完之后,问了一个更难的问题:看完了,然后呢?
一局结束,一切归零;一门知识学会,那个按钮就死了。
今天做的事,是给每一样东西接上下文。


写在前面:两条反馈,一个共同的字
06 收尾时,我给自己留了几个 TODO,但玩家先给回了反馈。两条:
- 「游戏内容太少」
- 「知识技术教导放了一次就再也不用,没什么意义」
第一反应是去加内容——更多事件、更多知识、更多野兽。但我停了一下,因为这两句话里藏着同一个字:
「然后呢?」
内容少,不是"事件不够多",是这一局结束之后,没有下一局。重开一次,和第一次一模一样。
知识没用,不是"数值太弱",是学会之后,这门知识就没有下文了。按钮变成一句"✓ 已学会",然后永远沉默。
知识没用,不是"数值太弱",是学会之后,这门知识就没有下文了。按钮变成一句"✓ 已学会",然后永远沉默。
所以今天没有加任何"新玩法"。今天只做一件事:给已有的东西,接上下文。


一、诊断一:一局 15 分钟,重开却和第一次一样
先看代码里"跨局"到底留了什么。答案是:Collection.lua 里的图鉴——39 条现象、累计局数、历史最高纪元。
也就是说,第二局和第一局唯一的区别是:开局时图鉴里多了几个亮点。
玩家不会为了"点亮图鉴"再玩一局。 图鉴是收集,不是成长。它给你"集齐"的欲望,
但不给你"我变强了"的实感。
但不给你"我变强了"的实感。
而 docs/总策划文档.md §三 里,其实早就写好了答案:
道基收益 = ⌊ (峰值人口 / 25) ^ 1.5 -- 规模:指数回报,鼓励做大
+ 最高纪元 × 4 -- 高度:文明走得多远
+ 累计聚落数 × 3 -- 广度:长出过多少聚落
+ 本局文明现象数 × 0.6 -- 探索:发现了多少
⌋
外加一张 6 条线的永久升级树。文档写好了,代码里一行都没有。
全库 grep 不到 “道基 / prestige / upgrade” 任何一个词。结算面板的注释甚至写着
「不再为转生面板留位」。
全库 grep 不到 “道基 / prestige / upgrade” 任何一个词。结算面板的注释甚至写着
「不再为转生面板留位」。
这是本项目最典型的病:设计文档跑在实现前面太远。 05 删掉过一版转生,
后来文档又把它写回来了,但没人去实现。
后来文档又把它写回来了,但没人去实现。


二、修复一:转生 / 道基 —— 外层循环
新增 Prestige.lua。原则是它不认识 World:
lua复制
lua-- Prestige 只持有跨局数据与数值公式,不 require World/Systems。 -- World 需要读它(神力上限/回复),若这里再 require 回去就成环。 -- 本局表现由 main / Render 在结算时组装好,通过 Prestige.Award 传入。
这个"依赖方向"是整个设计的地基。World → Prestige 是单向的,
所以 World 可以每帧从它读神力上限,而它自己保持纯净。
所以 World 可以每帧从它读神力上限,而它自己保持纯净。
2.1 道基:结算发放
结算时按公式发放,写进 prestige.json:
lua复制
luafunction Prestige.Award(summary) local gain = Prestige.Quote(summary) if gain > 0 then Prestige.daobase = Prestige.daobase + gain ... Prestige.Save() end return gain end
2.2 六条永久升级
| 升级 | 效果 | 每级 | 上限 | 基础成本 |
|---|---|---|---|---|
| 神启 | 神力上限 +15 | 15 | 8 级 | 3 |
| 恩泽 | 神力回复 +15% | 15% | 8 级 | 3 |
| 血脉 | 开局人口 +4 | 4 | 8 级 | 4 |
| 厚土 | 资源点容量 +15% | 15% | 6 级 | 5 |
| 先见 | 开局解锁全部工具组 | 一次性 | 1 级 | 12 |
| 遗泽 | 开局赠送篝火 + 资源 | 每级 +1 份 | 5 级 | 6 |
成本曲线 ×1.6~1.7。文档里那句话我抄在了代码注释里:
前期升级便宜(神启/恩泽 3 点起),让玩家第一次转生立刻能买到东西——
即时正反馈是增量游戏的生命线。
2.3 接入点:三个必须踩准的顺序
这类"跨局加成"最容易死在调用顺序上。三处:
| 位置 | 顺序要求 | 为什么 |
|---|---|---|
| Start() | Prestige.Load() 必须在 W.Generate() 之前 | 「厚土」影响地图资源容量,晚加载 = 本局不吃加成 |
| ResetGame() | 开局人口 = START_POP + StartPopBonus() 一次生成 | 二次调 SpawnInitial 会重置 nextId |
| ResetGame() | ApplyPrestige() 必须在 Tutorial.Reset() 之后 | 否则「先见」的跳过教学被 Reset 覆盖 |
第一版我把 ApplyPrestige 放在 Tutorial.Reset() 前面,「先见」失效了。
顺序错误不会报错,只会静默地不生效——这是最难查的一类 bug。
顺序错误不会报错,只会静默地不生效——这是最难查的一类 bug。
2.4 验证
22 项断言全过(公式、成本曲线、购买、满级、各加成查询、World 集成)。
其中一条值得记:
其中一条值得记:
[PASS] World 神力钳到新上限: got=130 want=130
「神启」2 级后,World.Update 真的把神力钳到了 130。跨局加成真的流进了模拟。


三、诊断二:知识教一次就再也没用
第二条反馈,我去读了 Knowledge.lua。真相很直白:
luaKnowledge.learned = {} -- id -> true
每门知识是一个二值开关。 学会之后:
lua复制
luaif learned then Text(..., "✓ 已学会", ...) -- 按钮变成一句墓碑铭文
学完只剩三个静态数值(采集 +50%、战斗 +50%、自愈 ×1.8)和一次性解锁。
没有任何"继续投入"的入口。
没有任何"继续投入"的入口。
玩家的感受完全准确:这不是数值太弱,是没有下文。
而设计文档里那句第一原则还立在那儿:
神不建造,神只传授知识。
所以深造也必须走"立碑 → 小人自己领悟"这条路,不能变成玩家直接升级。


四、修复二:知识深造(0/1/2/3 级)
核心:把二值开关改成等级。石碑不退休——玩家可以花更多神力让同一块碑"更深",
碑会重新变成"未被读懂"状态,小人必须再走过来读一遍。
碑会重新变成"未被读懂"状态,小人必须再走过来读一遍。
立碑(Lv1) → 小人领悟 → Lv1 生效
↓ 面板出现「⬆深造 ✨72」
深造 → 同一块碑刻纹重新暗下 → 小人必须再来读一遍 → 领悟 → Lv2
关键设计:深造不是"神直接给",而是让这块碑重新变得读不懂。
神能决定的仍然只有"立哪块碑、要不要更深"。
神能决定的仍然只有"立哪块碑、要不要更深"。
4.1 使用门槛:这是"用起来"的关键
深造到 Lv2 的前提是——他们真的用上了这门知识:
lua复制
lua-- 该知识解锁的设施,世界上至少建成了几座。 -- 没被用上的知识不许加深——这是"教了却用不上"的直接回应。 function Knowledge.UsedCount(id) ... end
Lv2 要 1 座设施,Lv3 要 3 座。知识 Lv1 本身就会驱动他们去建,所以门槛自然填满;
没被用上的知识,你也没法加深。 这直接回应了"教了却用不上"。
没被用上的知识,你也没法加深。 这直接回应了"教了却用不上"。
4.2 各级效果
| 知识 | Lv1 | Lv2 | Lv3 |
|---|---|---|---|
| 矿物 | 采矿、采石 +50% | 采石 +100% | 采石 +150% |
| 农耕 | 农田、采食 +40% | 采食 +80% | 采食 +130% |
| 建筑 | 住房 | 住房容量 +25% | +50%、时代资本 +10% |
| 冶炼 | 工坊、全图 +15% | 全图 +15% | 全图 +30% |
| 军事 | 瞭望塔 | 解锁兵营、战斗 +90% | 战斗 +130% |
| 医疗 | 自愈 ×1.8 | ×2.6 | ×3.4、时代资本 +10% |
面板不再显示"✓ 已学会",而是常驻的 Lv N/3 + 深造按钮 + 门槛进度。
整局都有理由回来点它。
整局都有理由回来点它。
4.3 一个我自己埋的 bug:知识连升三级
端到端测试时,日志里出现了这个:
[知识] 他们领悟了「农耕知识」Lv.1
[知识] 他们领悟了「农耕知识」Lv.2
[知识] 他们领悟了「农耕知识」Lv.3
[combo_e2e] 农耕 Lv1 于 14.8s
14.8 秒内,一门知识从 Lv1 连升到 Lv3。
根因是我上一轮改的:
lua复制
luafunction Knowledge.TryInsight(monolith, agent, dt) monolith.insightT = (monolith.insightT or 0) + dt if monolith.insightT >= InsightNeeded then Knowledge.Learn(monolith.knowledge) -- ← 从不归零! end end
v3 的知识是二值开关,Learn 自带幂等保护(学过就 return false)。
v4 改成等级制后,这个保护失效了——同一帧里多个围观小人各调一次,
一次连击把碑从 Lv1 一路顶到 Lv3。
v4 改成等级制后,这个保护失效了——同一帧里多个围观小人各调一次,
一次连击把碑从 Lv1 一路顶到 Lv3。
修法:领悟后归零 + 开头判 IsPending:
lua复制
luaif not Knowledge.IsPending(monolith) then return end ... monolith.insightT = 0 Knowledge.Learn(monolith.knowledge)
教训:把一个幂等的数据结构改成可累加的结构时,要逐个检查原来依赖"幂等"兜底的调用点。
这个 bug 是我自己引入的,而且是上一轮就该抓到的。
这个 bug 是我自己引入的,而且是上一轮就该抓到的。
4.4 另一类差一错误:Lv0 白拿加成
回归测试里,峰值人口从 58 掉到了 44。数值变了,说明有 bug。
追到 levelValue:
lua复制
lua-- 错:把等级 0 钳到索引 1 return arr[math.max(1, Knowledge.Level(id))] or default
效果表是"索引 = 等级"的,math.max(1, 0) 让它没学过知识也拿到了 Lv1 的加成。
神不教,小人白拿。
神不教,小人白拿。
改成 if lv < 1 then return default end 后,峰值回到 58。
教训:效果表的索引语义(索引=等级 vs 等级+1)一旦不一致,首尾都会错,
而且只有端到端数值回归能抓到。
而且只有端到端数值回归能抓到。


五、顺手修的崩溃:0.75% 的地图种子开不了局
跑回归时踩到一个崩溃:
ERROR: 资源簇有效格不足,请检查 GameBalanceConfig.MapConfig
写了个种子扫描脚本,400 个种子里 3 个失败。加上上下文信息后定位到 food 资源簇:
seed=467221 失败: 资源簇「food」有效格不足:17/18(中心 30,31,出生点 28,32)
根因:食物簇中心会按种子抖动 ±4 格。当它被抖到贴近出生点 (28,32) 时,
两个约束叠加吃掉了候选格:
两个约束叠加吃掉了候选格:
- 出生点 5 格内不放资源(ResourceSpawnMinDistance)
- 候选格必须与出生点连通
而搜索半径固定为 ClusterRadius = 5。中心离出生点越近,被排除区切掉的面积越大——
有效格从 18 掉到 16~17,放不下 18 个食物点,assert 直接终止游戏。
有效格从 18 掉到 16~17,放不下 18 个食物点,assert 直接终止游戏。
修法:有效格不足时逐环外扩搜索半径(最多 +4),够用就停。
lua复制
luafor extra = 0, maxExtra do local radius = map.ClusterRadius + extra points = {} -- ...收集候选格... if #points >= count then break end -- 够用就停,不改变正常种子的布局 end
为什么是外扩而不是放宽排除区:排除区保证"出生点附近无资源"是玩法需要;
外扩只影响极少数边界种子,正常种子布局完全不变。
外扩只影响极少数边界种子,正常种子布局完全不变。
验证:1500 个种子 0 失败(修复前 400 个有 3 个);
回归峰值 58、道路 56,与修复前逐字节一致——确认没误伤正常路径。
回归峰值 58、道路 56,与修复前逐字节一致——确认没误伤正常路径。


六、更深一层:知识组合(双碑共鸣)
深造解决了"知识学完还有下文"。但还有一层没做:两门知识之间,能长出什么?
这是"涌现"主题最直接的表达。设计原则:复合知识不由神给。
立 A 碑 → 小人领悟 A 立 B 碑 → 小人领悟 B
└──────┬──────────┘
两块碑开始"共鸣"(累积合成进度)
↓ 攒满
✦ 他们在两块碑之间看出了新的东西:「灌溉」
- 触发:两门父知识都 Lv≥1 → 合成进度开始累积(无需玩家点击)
- 空间策略:两块碑距离 ≤ ResonanceRadius(10 格)时,合成速度 ×2
- 不破坏第一原则:神只立了 A 碑和 B 碑,复合碑不是神立的
6.1 六门复合知识
| 复合 | 父知识 | 效果 |
|---|---|---|
| 灌溉 | 矿物+农耕 | 农田再生 ×0.6、食物采集 +30% |
| 石工 | 矿物+建筑 | 每座住房容量 +50% |
| 兵器 | 冶炼+军事 | 战斗力 +60% |
| 草药 | 农耕+医疗 | 自愈 ×2.2 |
| 机械 | 冶炼+建筑 | 时代资本 +15% |
| 军医 | 军事+医疗 | 战斗 +25%、自愈 ×1.5 |
6.2 一个差点让机制形同虚设的判定
第一版写完,小人根本不去读第二块碑。追到 Agent.lua:
lua复制
luaif not m.dead and m.kind == "monolith" and not Knowledge.Has(m.knowledge) then -- 让他们想去看碑
用的是 Has(知识是否学会)。深造成碑后 Has 仍为真 → 再没人去读 → 深造机制形同虚设。
改成 IsPending(目标等级未达成)后,循环才闭合。这类"用错了谓词"的 bug,
写代码时看不出,只有端到端跑起来才会暴露。
写代码时看不出,只有端到端跑起来才会暴露。


七、UI:复合徽章,和一次"终于能看见了"
复合知识的 UI 是知识面板下方的一行徽章。但这一节的真正内容,是我终于能在本地预览里验证 UI 了。
前几轮我一直说"UI 无法验证,被登录页挡住"。今天花了点时间啃它:
引导 JS 会把 URL 查询参数自动转成引擎参数:
?skip_login → -skip_login
所以只要加载 index.html?skip_login,就能跳过扫码登录直接进游戏。
(踩过的坑:WASM_PLAYER_CONFIG.force_welcome 虽然也传 -skip_login,
但同时把游戏 URL 指向了 TapTap 欢迎页,游戏根本不加载。)
(踩过的坑:WASM_PLAYER_CONFIG.force_welcome 虽然也传 -skip_login,
但同时把游戏 URL 指向了 TapTap 欢迎页,游戏根本不加载。)
能截图之后,一晚上抓出了 4 个纯靠读代码发现不了的 UI bug:
| 现象 | 根因 |
|---|---|
| 徽章只显示 3 门,其余消失 | 面板仅 168px 宽,"图标+百分比"横排放不下,超出的被 break 静默丢弃 |
| 悬停徽章不弹详情 | 悬停识别只认 tool_/know_ 前缀,漏了 combo_ |
| 态势面板中文腰斩成 7 个字 | 用 string.sub(text,1,23) 按字节截断,中文 3 字节/字 |
| ✦ 渲染成豆腐块 | MiSans 字体缺这个字形 |
第一个改成紧凑网格(图标 + 底部进度条),6 门也放得下;
第二个补上前缀;第三个新增按显示宽度截断的 TruncCN,顺带修好了原有的石碑行;
第四个换成 ★。
第二个补上前缀;第三个新增按显示宽度截断的 TruncCN,顺带修好了原有的石碑行;
第四个换成 ★。
这一条是今天最有价值的经验:UI 的问题,读代码是发现不了的。
我自己写的"图标+百分比"横排,在代码里读起来完全合理——只有画到屏幕上,
才会看到它被截断。
我自己写的"图标+百分比"横排,在代码里读起来完全合理——只有画到屏幕上,
才会看到它被截断。


八、最后一环:跨局继承(文明的记忆)
知识能深造、能组合了。但一局结束,Knowledge.Reset() 把它们全部清空——
转生之后,上一世想出来的东西一点都没留下。
转生之后,上一世想出来的东西一点都没留下。
所以最后补上:复合知识作为"文明的记忆"跨局保留。
- Prestige 新增 knownCombos 表,持久化进 prestige.json
- 涌现时记一笔;这一世把两门父知识重新教会后,立即点亮(跳过 60 秒合成)
设计取舍(和玩家确认过):不保留未完成进度、不开局即生效。
理由是机制自洽——复合知识是"父知识之间长出来的",父知识不在时它没有载体。
一旦父知识回来就"想起来"。
理由是机制自洽——复合知识是"父知识之间长出来的",父知识不在时它没有载体。
一旦父知识回来就"想起来"。
文案也区分开:继承时是「他们想起了X」,而不是「他们自己看出了X」。
8.1 两局端到端
| 第 1 局 | 第 2 局(转生) | |
|---|---|---|
| 灌溉达成 | 涌现 @44.8s | 继承 @15.4s |
| 日志 | 「他们从两门之间看出了灌溉」 | 「他们想起了灌溉——上一世想过的东西」 |
第 2 局快了一倍多,因为父知识一学会就立刻想起,不用再攒 60 秒。
8.2 顺手修的两个 UI 问题
加了页脚之后,截图又抓到两个:
- 转生面板页脚重叠:6 行升级的自适应行高把新页脚盖住了 → 预留页脚空间
- 🧠 又是豆腐块:换成已验证可渲染的 🔗
同一个字体问题,一天之内踩了两次。 记下了:所有新增的 emoji 都要先截图确认。


九、当前状态
| 项 | 数值 |
|---|---|
| 知识系统 | 6 门 × 3 级(深造)+ 6 门复合(组合)+ 跨局继承 |
| 外层循环 | 新增:道基 + 6 条永久升级 |
| 单局时长 | 15 分钟(不变) |
| 地图种子崩溃率 | 0.75% → 0 (1500 种子验证) |
| 回归基线 | 峰值 58 / 道路 56(多轮改动后保持一致) |
| 本地预览 | 首次打通(?skip_login 绕过登录) |


十、下一步
- [ ] 拆分 Render.lua:3661 行,早就该拆了
- [ ] 觉醒/通天塔震荡:04 记过,06 修了一半,仍有反复
- [ ] 战争率:冲突判定限定在不同部落之间
- [ ] 发布素材:project.json 里 icon/screenshots/promotional_image 仍全为空
- [ ] 图鉴收录复合知识(目前只进"文明的记忆",未进图鉴)


写在最后
06 我写的是:神教了知识,但如果玩家看不见小人学会的样子,这个游戏是哑的。
今天想补上它的下一句:
看见了,然后呢?
一次好的体验,必须留下点什么——留下的东西,必须让下一次不一样。
一局 15 分钟,玩完归零,那它就只是一次体验。
一门知识学会就死,那它就只是一个数值。
一门知识学会就死,那它就只是一个数值。
今天做的所有事,本质上是同一件:让"然后呢"有一个答案。
知识学完 → 还能更深;两门知识 → 还能合出第三种;一局结束 → 他们还记得。
知识学完 → 还能更深;两门知识 → 还能合出第三种;一局结束 → 他们还记得。
一个增量游戏的核心从来不是"内容多",而是复利:
你做的每一件事,都该让下一步更容易一点。
你做的每一件事,都该让下一步更容易一点。
今天没有加任何新玩法。今天只是给每一样东西,接上了下文。#聚光灯gamejam开发者日志












