[架构/性能] 方案 F:模拟与 rAF 解耦 —— 渲染一慢就丢模拟时间,20 tps 这个读数本身就是渲染耗时的间接产物 #19
Labels
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
No due date set.
Blocks
#16 [性能] 渲染主循环掉到 20 tps:零视口剔除(88.6% 白画)+ 图集页切换导致单帧最高 3077 次 draw call
troytt/diablo2-web
Reference: troytt/diablo2-web#19
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
拆自 #16 的方案 F。这条是 A→C 之后真正还剩的结构性问题,建议 P1。
问题
src/sim/loop.ts的GameLoop.start()完全由requestAnimationFrame驱动,onRender是同步的。渲染一慢,rAF 间隔就被拉长,累加器超过tickMs * maxCatchUp(40 × 5 = 200 ms)之后被直接清零,这段模拟时间就丢了。后果有两层:
方案
setInterval/ 递归setTimeout,rAF 只负责画 + 插值。改动小,能立刻切断"渲染慢 → 模拟丢时间"这条链路。代价是定时器精度受后台标签页节流影响。项目里已经有
src/net/lockstep.ts,确定性定步长模拟天然适配 Worker —— 状态是可序列化的,输入是离散的,本来就是为了跨端一致性设计的。验收
onRender里塞一个 50 ms 的忙等,tickRate仍然稳定在 25(±0.5),world.tick的推进速率不受影响。GameLoop(或其替代)喂一串故意拉长的时间戳,断言累加器不再出现整段清零。依赖
建议在 A→C(
4cc49a0)之后做,因为现在才有真实的帧耗时读数可以对照。方案 F(模拟与 rAF 解耦)修复完成并验证通过
fix/issue-19167928a31f469b74896e8fc9ec947b50b0fd7b2asrc/sim/loop.ts中引入自纠偏定时器驱动定步长模拟(25 ticks/sec),requestAnimationFrame专职负责画面绘制(onRender)与插值计算;tickRate仍稳定在 25(±0.5),world.tick推进速率完全不受渲染拖累;src/scene/act-scene.ts中彻底将 HUD 的「模拟 TPS」与「渲染 FPS / 帧耗时」分离显示(如sim: 25.0 tps | render: 60 fps (16.6ms)),消除指标混淆;tests/loop.test.ts(包含 25 tps 定步长断言、50ms 渲染卡顿容忍断言、累加器平滑恢复、生命周期清理等 6 项测试全绿);npx tsc --noEmit0 报错,全量 34 个测试套件 636 个测试全部通过。