Skip to content

模拟器、倍速与慢放

模型的 main_c 定义“一次物理子步”,模拟器定义“一游戏刻执行哪些子步、执行几次,以及什么时候同步”。把这两个职责混在一起,最容易造成重复重力、倍速失真和落地抖动。

模拟器状态

text
simulator {
  global_sim_mod
  global_inv_dt
  global_set_inv_dt
  global_rate
  tick_funcs[]
  sync_funcs[]
}
字段含义
global_rate每个 Minecraft tick 执行的模拟子步数
global_inv_dt时间拆分分母
global_set_inv_dt在完整周期边界切换到的新分母
global_sim_mod当前拆分相位
tick_funcs每个子步运行的回调
sync_funcs所有子步结束后每游戏刻运行一次的回调

模拟时间倍率为:

text
global_rate / global_inv_dt

三种常用设置

rateinv_dt效果注意
11正常 1×默认
41每 tick 四子步,4×成本约四倍
14四个游戏刻完成一轮,0.25×需要 slow key/mov 契约
0任意暂停模拟子步sync_funcs 仍可能运行

global_rate=0_stop 不同:前者保留调度但不进入 main_loop,后者清除计划函数。

每轮为什么先恢复常量

不同模拟器可以有不同重力、摩擦和反弹参数,但底层假玩家是共享的。正确顺序是:

mcfunction
function vve:_consts
# 再覆盖本模拟器的环境参数
scoreboard players set vve_gravity int 120

若不先恢复默认常量,前一个模拟器的参数会泄漏到下一个环境。一个模拟器完成 _get → _consts → main → _store 前,不要嵌套另一个模拟器。

运动拆解

“拆解”指把完整帧的职责分开调度:

  • main_force:更新物理与响应;
  • main_sync:把结果同步给世界/显示;
  • sync_funcs:把昂贵但只需每游戏刻一次的显示或聚合工作移出高速子步。

例如 4× 子步时,物理可能执行四次,但 display 更新只需一次。前提是所用模型确实提供对应分段入口,且两段合起来与完整帧语义一致。

运动慢放

VVE 的慢放不是“每四 tick 才突然跑一次完整 main”。这种做法会让画面阶跃、碰撞点跨越更远。源码中的 main_slow_keymain_slow_mov 将一个物理周期分成:

  • 关键步:在周期边界执行介质探测、力学结算和新的关键状态;
  • 运动步:在中间 tick 按拆分时间推进运动,使显示连续。

vve:sim_slow 只保存附着在外部实体上的 vve_rate 等慢放状态;它本身不遍历或调度物理对象。调度仍由模拟器或业务函数负责。

只切换已完成周期的分母

global_set_inv_dt 用于把新拆分数延迟到相位回到边界时生效。若在半个周期中直接改 global_inv_dt,可能跳相位、重复关键步或漏掉结算。

暂停、单步与页面播放

在本站视窗中,Play/Pause/Step 控制的是 Sandbox 20 TPS 模拟。tickFunction 会串行加入每个沙盒 tick;它不会与 cell 命令并发修改世界。页面隐藏时自动暂停,卡顿时最多补算有限 tick,避免后台无限追赶。

选择调度策略

  • 普通对象少:每 tick 直接 main_c,最容易验证。
  • 需要高速稳定性:增加 global_rate 做子步,但同步移出子步。
  • 需要慢镜头:使用模型提供的 slow key/mov,不要简单跳帧。
  • 多区域/多规则:使用多个模拟器,但每个对象只能属于一个活动调度路径。
  • 远处/静止对象:在业务层跳过主程序,见性能、静体与子系统

VVE 由小豆 8593 开发;本站是面向学习与查阅的增强文档。