固定步长 30Hz:一个让 bug 可复现的决定
为什么选 30Hz 而不是 60Hz,累加器怎么写才不会死亡螺旋,以及插值为什么只能发生在表现层。
AI 摘要
确定游戏逻辑层的固定模拟频率并正确实现:30Hz是在低端机余量与手感之间算出的工程折中点;累加器需钳制deltaTime防死亡螺旋、限制每帧补tick数防卡死;插值只能在渲染层做且绝不能写回Sim,否则确定性破产;输入需按按下沿在tick边界采样。
Featured
写给自己看的架构笔记,恰好也能给别人看懂。
为什么选 30Hz 而不是 60Hz,累加器怎么写才不会死亡螺旋,以及插值为什么只能发生在表现层。
AI 摘要
确定游戏逻辑层的固定模拟频率并正确实现:30Hz是在低端机余量与手感之间算出的工程折中点;累加器需钳制deltaTime防死亡螺旋、限制每帧补tick数防卡死;插值只能在渲染层做且绝不能写回Sim,否则确定性破产;输入需按按下沿在tick边界采样。
Projects
都还在进行中,包括这个站点本身。
2025年11月 — 至今
Unity 2022.3 的 Roguelike 割草 / Horde-Survival。核心是一套纯 C# 的确定性模拟层:30Hz 固定步长、表现层与逻辑层严格分离、所有战斗可重放。
Notes
运算符与类型别名、闭包与自增陷阱、结构体相等性与比较器、位运算与位标记、StringBuilder 线程安全,以及分页与序列化细节。
MenuItem 快捷键、.meta 与 CRLF 引发的预制体引用错误、VS 提示丢失排查,以及一批项目层面的优化实践与架构经验。
activeInHierarchy、协程与激活状态、DontDestroyOnLoad 的渲染陷阱、Time 家族字段与 FixedUpdate,以及 Animator 刷新时机的实践经验。
理清 Layer、Sorting Layer、Order in Layer 与 Sibling Index 的职责边界,以及 UI 射线检测、遮罩和透明度控制的正确做法。
Spine 换肤与灰度、粒子透明度渐隐、Renderer 与 Graphic 的材质实例化规则、CustomMaterialOverride 换材质,以及纹理内存与资源规格。
Now
在做《Way Of The Warrior 3D》—— 一个 Unity 2022.3 的 Roguelike 割草游戏。
/now 页面的内容会随进度更新,这里展示的永远是"当下",不是目标。
Now Playing
手上在做的项目与在玩的游戏。
Unity 2022.3 · PC
进行中
自研 Roguelike 割草,确定性模拟优先于性能。
Timeline
项目、文章与关键决策,按时间排。
决定把战斗逻辑从 MonoBehaviour 里全抽出来
M3 收尾时遇到一个概率三十分之一的抖动 bug,根因是 Update 和 FixedUpdate 读了不同的 deltaTime。抽层花了两周。
为什么选 30Hz 而不是 60Hz,累加器怎么写才不会死亡螺旋,以及插值为什么只能发生在表现层。
实测 300 敌人单 tick 成本 9.2ms。30Hz 给到 33ms 预算,留 3.6 倍余量;20Hz 手感开始发钝。
Unity 2022.3 的 Roguelike 割草 / Horde-Survival。核心是一套纯 C# 的确定性模拟层:30Hz 固定步长、表现层与逻辑层严格分离、所有战斗可重放。