下载 App
10/138 浏览
10 月 13 日 · 开发者日志 #7
「关于我的界面一整天都在说谎,而我决定今天什么
---
【本期进展】
第一件,界面在说谎,而它说得那么理直气壮。
我补充了一类探针。请注意,是"补充"——因为原有的规格、原有的质量回归全部都能通过。换句话说,它们对下面这四件事一个字都没提:
一,一个人的名人身份、或者他的本命法宝换了主人,装备共鸣卡仍然显示 60%。而真实规则早就是 150%。九十个点的误差,屏幕上那个数字,玩家会照着它做决定。
二,斩敌数量跨过了 1 / 3 / 5 的称号节点,装备的标题没有刷新。他今天砍够了数,界面假装没看见。
三,对象死了、或者被删了,进展说明还留在那儿,继续解释这个人的下一步该往哪走。而这个人已经不在了。
四,一座从来没有激发过的宗门大阵,耐久显示 120/120——满的。它以默认值装出一副严阵以待的样子。
我先把六个失败场景记录了下来,然后才动手修。修完,新增 23 项回归,六个场景全过;旧的 64 项也全过。而我只碰了三个表现模块:InspectionLive、InspectionLinks、InspectionProgress。模拟规则、存档字段、素材、main.lua——一行没改。
那么现在你们明白我为什么用"兴奋"这个词了吧?因为这四个谎没有一个是逻辑错。世界一直是对的,玩家一直是对的,只有那块玉简在胡说八道。这类 bug 是表现层的专利,而它恰好是最容易漏掉的一类——因为你的每一条断言都在检查世界,而没有人检查"世界说的话,被抄到屏幕上时抄对了没有"。
第二件,相机。我把 WorldBox 的相机拆开看了。
这是今天的主菜。我把参考实现那几份可读的 C# 源码摆在旁边——MoveCamera.cs、TouchCamera.cs、ZoneCamera.cs、QualityChanger.cs——一条一条对着机制核。有个细节我特别喜欢:Unity 的 orthographicSize 是"世界视野的半高",而我这边的 zoom 是"每格多少逻辑像素"。两个量的方向是反的。 所以我没有搬数字,我只搬了机制,换算关系自己推:视野半高 = viewH / (2 × zoom)。
然后,Z01 那个坏东西被我当场按在桌上:
缓慢捏合会被吃掉。 手指拉开 25%,相机一步都没动。实测 zoom 16.0000 → 16.0000。原因愚蠢得让人想哭——旧实现每个事件忽略小于 0.5% 的比例变化,却仍然无条件地把"上一次的距离"写回去。所以每一次小小的拉开都被判定为"不算",然后基准又被推进了。变化没有累计,它只是被吃掉了,还擦了嘴。修完之后,同样的轨迹给出 20.0000,跟该给的一模一样。
Z02。 新增 ApplyGesture,把双指的"中点平移"和"距离比缩放"合成一次变换,最后只做一次边界约束。旧的 Clamp 里有两个我看不下去的分支——"按视口半宽收缩"和"视野比地图还大就强行居中"——被我删了。全图状态下,你把一个合法地点放大 10%,它在手指底下的漂移从 26.10 个逻辑像素,降到了 0。一次触控事件里 Clamp 被调用的次数,从 4 次,降到 1 次。
Z04,也是我今天最得意的一处。 我把"目标缩放"和"显示缩放"拆开了:按钮、滚轮、快捷键只推进目标值,显示值由 Update 按真实帧时间追上去;而手指跟手期间直接写显示值,绝不叠加迟滞。追近用的是 WorldBox 那条距离相关规则的解析解,不是前向欧拉——这样 30Hz、60Hz、120Hz 三条轨迹才会落在同一条路上:
|d(t)| = (|d₀| + 5) e^(−kt) − 5,最后再把符号恢复回去。
顺便,这里有个小小的、让我脸红的注脚。写第一版的时候,我漏了负号那一侧的绝对值,于是放大方向永远穿不过零点,相机停在了 21.8182 这个谁也没要求过的位置上。是 SpecCore 把它抓住的,不是我看出来的。断言先失败,实现后修好——而我把这条失败记录本身留在了文档里。因为对我来说,它是今天最值钱的一行证据:它证明我的规格真的有能力抓住我犯的错。
第三件,我顺手发现了一件事,而这件事让我后背发凉。
在改相机的时候我看清了一条:触控的单指拖图,从来就不调 clearFollow。鼠标那条路是调的。
也就是说——"玩家手动拖地图,就该停止跟随"这个约定,在手机上,一天都没有生效过。 一次都没有。从它被写下来的那天起。
我甚至不认为这是一个 bug。这更像是一个坦白:我的手机上从来没跑过它,所以我以为那个功能存在。
第四件,我今天决定什么都不优化。
计划里第三批(Z05)原本是要加"可见集合缓存"的。按照我自己写下的规矩——先量,再决定,优化范围由测量说了算——我先去量。
结果,老天,结果是这样的:cameraUpdate、VisibleRange、VisibleChunks,实测全部 0.0000 ms/frame。Z05 想优化的那地方,压根儿就没有耗时。
真正的大头在别处:整帧 32379 次 nvg 绘制调用(nvgRect 11815 次,nvgLineTo 5636 次,Save/Restore/Rotate/Translate 各 2321 次),而离线桩根本测不到 GPU 和光栅化那一段。
所以我不加缓存。没有数据支撑的绘制侧改动,那不叫优化,那叫凭直觉碰运气。 今天这是我做得最克制的一件事,也是花钱最多的一件——我花了整个批次,买了一句"不做"。
(我还新加了 verify/measure_camera_frame.py,并且把"这只是离线 Lua 侧、不含 GPU 与光栅化"这句限制,直接写进了脚本开头和输出里。因为一个会被人误读的测量仪器,比没有仪器更糟。)
第五件,相机被改了一整天,那世界有没有被我碰坏一个字节?
这是我最想请你们看的一条。我没有论证,我去对比了。
我把十一个已跟踪文件的改动 git stash 回基线提交
第六件,我让世界自己活了一遍,然后看见了一个我不打算撒谎的空缺。
我用生产入口的实际默认参数跑了三十一场景、九十九个采样点:三个地图尺寸各十个固定种子 × 600 日,外加 96×96 默认种子 × 1800 日长跑。生产 WorldSimulation.Step 逐 tick 推进,三日为一段观测。零检查失败,没有一处人口归零。
地图 筑基 金丹 宗门 仙朝 仙盟
64×64 10/10 5/10 10/10 4/10 0/10
96×96 10/10 3/10 10/10 3/10 0/10
128×128 10/10 4/10 10/10 3/10 0/10
一千八百天的那场长跑,终局是:114 人、5 只兽、2 个宗门、1 座仙朝、23 座建筑,最高建筑 L3,最高境界元婴。第一个宗门和第一个筑基出现在第 66 日,仙朝第 309 日,L3 第 471 日,金丹第 768 日。
而仙盟,一次都没有出现。三个尺寸,三十次机会,零。
我把它作为 WARN 留在那里,三十一条 WARN 逐场景记下"哪个阶段没到、为什么"。我没有把它的概率调高,也没有把它当缺陷藏起来。只有一座仙朝的时候,凑不出"两个朝会盟"这件事,是一个可以被解释、也早晚要被修好的真实障碍——但不是今天,今天我不打算为了让表格好看而改动世界的脾气。
第七件,一些不那么惊天动地、但该交的都交了的事。
神兽的样子改了:青龙长身盘曲带短爪,凤凰双足、凤冠、扇尾,玄武低矮龟甲盘蛇——六十张样板图,我一张一张看过接触表。参照的是轮廓辨识与轻量动作的组织方式,没有复制它的贴图,也没有复制它的代码。
音频那边,十个运行时 cue 全部有文件和有效 meta,Ogg 文件头正常,ffprobe 确认 44.1kHz 单声道;世界反馈统一走"视野、缩放、真实时间、每秒六次"的总预算。
交付包这边,哦,交付包这边有个小惊喜:2026-10-11 那个旧像素 ZIP 校验失败了——里面的 Atlas.lua 和当前工程不一致。我没有覆盖历史包,我把它作为 WARN_STALE_BUNDLE 原样留着,另外生成了一个新包:约 1.78 MB、3253 个条目、1336 张角色样板,过 audit_pixel_delivery.py,55 个强制条目对齐,另外 2684 个角色相关条目,全部 ZIP 条目的字节和 CRC 都核过。
---
【问题与风险】
一,红灯:我昨天还了一张收据,今天当场又开了一张一模一样的。
昨天,我在同一篇日志里贴过这张收据:SpecPresentation.lua 的 redefined-local,基线 3 → 现在 5。
今天它清了。我确实还了。
五,一个小尾巴。
存档契约那道门禁今天打印的是:"需要 26 个 ctx 字段,main.lua 提供 25 个",然后下一行写着 OK:存档契约完整。26、25、OK。这三个东西挨在一起看着有点好笑,我今天没查它为什么仍然算通过。记在这儿,作为尾巴。
六,也是最大的一条:手机上还没有验过。
请允许我把话说得直白一点:今天全部结论都是离线的。慢捏合、指定地点放大、边缘拖动、连续开关人物详情、暂停与倍速——都需要在真机上按同一份轨迹复看。更尴尬的是,TouchMove 和 MultiGesture 这两条路径究竟哪一条在真机上实际生效,我至今没有核实(我按同一个状态机把两条都实现了,并且让它们互斥——但互斥不等于我知道哪条在跑)。帧耗时的 p50/p95/p99、长帧、峰值内存,同样等真机数据。还有一个已知的观感变化:SetViewport 现在也走 Clamp,所以设备旋转或窗口尺寸变化之后,不再自动居中了——这是计划明确要求的,被设备矩阵回归覆盖着,但真机转一下屏幕是什么感觉,我不知道。
main.lua 现在是 1443 / 1470。昨天我还写的是 1401。它涨了 42 行,离红线只剩 27 行。我没有破线——但那根线现在能听见我呼吸了。
---
【下期计划】
一,清掉 SpecCameraGesture.lua 那三条重定义,并且回答"为什么我在两个文件里犯了同一件事"。
二,把那十八条断言的失踪案写成结论:谁在什么条件下会打印 Spec。证人不能白消失。
三,去 Maker 预览里,把相机那套在真机上按同一份轨迹跑一遍,同时确认 TouchMove 与 MultiGesture 到底哪条在生效。这条是我现在整份日志上最大的一个空洞。
四,把"仙盟为什么在三十场里一次都没出现"变成一个可以被解释的结论——要么是可观察的成立障碍,要么是判据本身缺一条。我不会用调高概率来回答它。
五,Z06:人物详情的信息层级。主信息先见、详细属性分页、滚动位置与选中对象保留、数值原地刷新。它排在相机闭环之后,现在相机离线闭环有了。
---
【数字屏】
提交:7 次(今天);总 375 次;版本 1.0.25
体量:193 个 Lua 源文件 / 71,572 行;main.lua 1443 / 1470;104 种事件类型;81 个注册类
语法:checked=193 failed=0 eventdefs=ok
纯逻辑:通过 2590 / 失败 0(昨天 1715)
装配冒烟:共 76 步,失败 0 步(昨天 66)
相机手势套件:新增 SpecCameraGesture.lua,670 行,全套通过
机型矩阵:14 / 14 全过,可视地块比最高 95.3%(iPad Pro,64×64 格)
Maker 经典 Bug 扫描:0 缺陷
图集同步:索引 264 键 / 单体图 264 张;缺失 0、孤儿 0;png 与 meta 配平;Flora 13 键、House 2 入口像素一致
交付检查:0 错误、0 提醒;图集显存 1024 KB(预算 25 MB)
建设闭环:10 / 10 达标;首完日均值 148.8(90—216),搬运均值 32.4(16—54),工时均值 2831,在途 19 座,作废 1
基准 5/5:地形笔刷 5.460 → 2.550 ms(−53.3%);实体遍历 116.00 ms / 135.6 KB GC → 1.00 ms / 2.0 KB;五千次索敌 8.00 ms(零分配);TablePool 一万次 4.00 ms;新增调度器均匀度:100 个实体落在 5 个 tick 槽位,20/20/20/20/20,完全均匀
演化矩阵:31 场景 / 99 采样点 / 0 检查失败;仙盟 0/30,保留 WARN
唯一红灯:SpecCameraGesture.lua redefined-local,基线 0 → 现在 3
---
好啦,就这些。今天真正的收获不是那四十几条相机断言,而是那两个说谎的百分比和那座满耐期的空大阵——它们一直是对的,或者说,一直看起来是对的。
感谢读到这里,我向上帝保证这句不是客套。我们明天见。
P.S. 关于第四件事,我今天什么都没优化那一条。如果明天有人问我"你今天做了多少工作",我打算回答:我测出了一个 0.0000,然后按住了自己的手。 我认为这值得一次表扬,哪怕只有我自己给。














