下载 App
开发日志3 · 2026-10-06 ~ 10-07
10/077 浏览
# 这两天做了什么
六件事:**让文字会呼吸**、**给世界配上声音**、**把世界观焊进玩法**、**修几个藏得很深的 bug**、**做排行榜**、**一次严重的崩溃**。
最后一件差点让游戏完全打不开。
---
## 一、文字会呼吸了
### 打字机效果
之前叙事和弹窗的文字是**一次性全部出现**的,读起来像在念说明书。
改成了逐字显示。点击正文可以跳过——不想等的玩家不受影响。
### 一个我没想到的连锁反应
做完之后发现,**长文本会溢出弹窗边框**。
一开始以为是打字机的 bug,查下来才发现:**弹窗的正文标签从来没设过"允许换行"**。
中文和英文不一样——英文有空格,排版系统能在空格处断行。**中文一整句没有空格**,不显式开启换行,它就会横着一直铺出去。
有意思的是,**开场叙事的标签早就设了**,所以那一块一直正常。**只有事件、结局、时代这三个弹窗漏了**——因为它们是另一处代码写的。
同一个功能,两处实现,一处对一处错。这种问题光看代码很难发现,**要真的把长句子丢进去才会暴露**。
---
## 二、给世界配上声音
做了 10 个音效和 5 首配乐,按场景分。
音效覆盖了拖卡、出牌、推演、组合技、事件、错误、成就、时代、绝境、离线报告。后来又补了两个:火种消费、世界切换。
### 一个技术决定
音量控制**没有写死在每次播放里**,而是走引擎的**音频总线**。
区别在哪?
如果写死在播放调用里,**调音量时正在播的那首曲子不会变**——得等它播完下一首才生效。而走总线,**改一下立刻全场生效**。
这个决定后来直接受益于下面这件事。
### 玩家能自己调
在用户中心加了两个滑条:配乐音量、音效音量。**拖动时即时生效**——因为走的是总线。
设置**存在云存档里**,换设备也保留。
### 一个当时没发现、后来才补的问题
音效是分批生成的,**每个都独立,没有统一的响度基准**。
后来一测才发现:**最响的和最轻的差了 36 分贝**——大约 60 倍的音量差。
更糟的是,**最轻的那个恰恰是最常播放的**(拖卡和点选都用它)。最常响的反而最听不见。
这不是玩家调总音量能解决的——调小了,别的又太轻。所以做了**响度归一化**:按分类统一基准,但**保留"该突出的仍然突出"**(组合技、绝境这些强调音依旧更响)。
差距从 36 分贝收到 4 分贝。
---
## 三、把世界观焊进玩法
之前的世界观是"贴在游戏外面的"——开场念一段,然后就没了。
这次做了两件事:
**① 给每个机制配上"它在这个故事里是什么"**
比如"回合"不只是回合制,而是**守夜人拨动一次命运的齿轮,看向人间就是十年**;"火种"不是从文明收的税,而是**守夜人燃烧自己灵魂散出的余温**。
**② 把多世界改成了"灯台"**
原本是冷冰冰的"世界 A、世界 B"。改成:
- 每个世界 = **守夜人点燃的一盏灯**
- 创建新世界 = **点燃新火种**
- 切换世界 = **移开视线**
**叙事和技术在这里刚好对上了**:火种本来就是"守夜人自己的东西",所以技术上把它改成**账号级、跨世界共享**,和"它是你的本源"完全一致。
---
## 四、几个藏得很深的 bug
### 世界列表不刷新
现象:创建了新世界,打开列表却看不到。
查下来是个**很典型的坑**:界面库的子节点,**只在构造时读取一次**。之后再怎么改那个"子节点列表",对已经渲染出来的东西**毫无影响**。
所以原来的"清空 + 追加"代码,**等于什么都没做**。
### 存档卡顿
玩家反馈"存档响应和切换速度太慢"。
看了日志,问题很清楚:**每拖一张卡就上传一次整个存档**。一局下来上传几十次。
改成**本地立即写 + 云端合并上传**。
关键认识是:**本地缓存才是防丢的关键**,云端只是为了换设备。原来为了"保险"每次都传云端,代价是每次操作都卡一下。
### 节流带来的新问题
改成节流后,**云端会比本地旧**。如果读档时直接用云端,就会**覆盖掉本地更新的进度**。
所以加了**时间戳比对**——读档时比较云端和本地哪个更新,取新的那份。
**这是节流能安全实施的前提,不能省。**
---
## 五、排行榜
做了存活回合数的排行榜。
### 分数选什么,想了挺久
候选有:存活回合数、科技值、数值总和。
最后选了**存活回合数**,因为它**一句话说得清**("我的文明活了 87 个十年")、**和玩法正相关**、**天然封顶**。
### 一条容易忽略的规则
排行榜**只记历史最高**,而且**只增不减**。
如果记"当前世界",玩家切到低分世界**排名就会掉**——这显然不对。
### 上线后暴露的问题
第一版做完,测试时发现排行榜**是空的**。
原因是:分数**只在结局触发时上传一次**。玩家中途退出,成绩全丢;没打到结局,就永远不上榜。
改成了**本地实时更新 + 云端节流上传**——每回合都记录,但上传做节流,退出和结局时强制推上去。
### 一个更危险的隐患
改的时候发现:如果**云端同步失败**(比如断网),本地记录还是 0。这时提交一个很小的值,会**把云端的真实纪录覆盖掉**。
**这会毁掉玩家的历史成绩。**
所以加了保护:**同步没成功之前,一律拒绝上传**。宁可不上传,也不能传错。
---
## 六、世界的历程
给文明加了一本"传记"。
玩家在左上角能常驻看到最近几条,点开右上角能看到完整记录:**你的抉择、遭遇的事件、迈入的时代、最终结局**。
改之前,那一块显示的是"屏幕日志"——**临时操作提示,看一眼就没用了**。换成历程之后,玩家随时能看到**文明走过的路**。
---
## 七、玩法内容扩充
### 卡牌从 10 张加到 17 张
原来的卡**只有"好坏"之分**——丰饶是好牌,天灾是坏牌。
新加的三类引入了**取舍**:
- **扩张卡**:高收益高代价(比如烧林开荒,资源暴增但推高混乱)
- **稳定卡**:低风险控场
- **高风险卡**:比如"起义"——用混乱换资源,**玩家可以主动引爆危机**
### 组合技从 3 个加到 6 个
新卡带来了新的组合空间。
### 事件从"纯数值"变成"要抉择"
原来事件都是被动接受。现在加了几类**二选一事件**——弹窗给两个选项,各带效果预览。
**没有绝对优劣**,取决于你当前的处境。
### 一处公式改动
查数值时发现一个结构性问题:**资源消耗是线性的**,所以中期资源会严重过剩——卡牌"丰饶"失去意义,资源类事件永远不触发。
改成了**超线性**(叠加一个人口的平方项)。**前期手感完全不变**,只在人口膨胀后形成压力。
---
## 八、一次严重的崩溃
改完一堆功能,测试时**游戏完全打不开了**。
报错是 `attempt to call a string value`——听起来莫名其妙。
### 根因
我建了两个**同名**的模块:一个在根目录,一个在子目录里。子目录那个要引用根目录那个,**但引擎解析到了它自己**。
于是变成**自己引用自己**,拿到一个不完整的返回值,一调用就炸。
### 修法
给子目录的模块改名。
### 顺带排掉一个定时炸弹
检查时发现**还有一对同名模块**。它**现在没炸**——因为那个模块恰好没有引用自己。
**但这是运气。** 以后谁加一行引用,就会重演同样的崩溃。一并改掉了。
**教训**:拆文件时只顾着"名字贴切",没考虑**引擎的模块解析是全局的**。
---
## 九、包体瘦身
修完崩溃,发现游戏**还是进不去**——这次是**包太大,加载超时**。
查下来:**40 兆的包里,有一半是废料**。
那是我之前生成的一批**建模参考图**(游戏里根本不用,代码里也没有任何引用),却被打进了包。
清掉之后**又发现配乐码率过高**——5 首曲子占了 16 兆。这类氛围音乐没有高频细节,**降码率听感几乎无差**。
最终**从 40 兆压到 13 兆**。
---
## 十、今天的几点体会
**1. 同一个功能的两处实现,往往只有一处是对的**
弹窗文字溢出那个 bug,根源是"叙事标签设了换行、弹窗标签没设"。
**同一个需求写在两个地方,迟早会分叉。**
**2. 性能问题的根因经常是"做多了",不是"做慢了"**
存档卡顿不是因为代码写得慢,而是**每次都做了一件没必要那么频繁做的事**。
改法不是优化那件事,而是**降低它的频率**。
**3. 优化一定要想清楚"安全性靠什么保证"**
把上传改成节流,性能好了,但**引入了"云端可能比本地旧"的新风险**。
如果只做前半截,就会变成"跑得很快,但偶尔丢进度"——**比原来更糟**。
**4. 命名要服从"工具的规则",不是"我的直觉"**
模块重名那个崩溃,我起名时只想着"这个名字最贴切"。
但**引擎的模块解析是全局的**——两个同名文件,谁引用谁都说不清。
**给文件起名,不只是给人看的,也是给机器看的。**
---
## 十一、当前进度
**已完成**
- 打字机效果
- 音频系统 + 音量设置 + 响度归一化
- 世界观整合、多世界叙事化
- 火种跨世界共享
- 存档性能优化
- 排行榜(存活回合数,实时更新)
- 世界历程
- 卡牌 17 张、组合技 6 个、二选一事件
- 包体瘦身(40M → 13M)
**接下来**
- **数值平衡实测** ← 仍然是最高优先级
- 3D 模型替换(美术已在进行)
- 更多结局










