这个问题是特定于反应 - 香蕉和具有物理和视觉组件(例如游戏)的实时模拟。如何在反应香蕉中实现游戏循环?
根据Fix Your Timestep!设置游戏循环的理想方式(假设物理需要可重现),您需要帧之间的固定时间步长。考虑一些实际的并发症后,笔者来到这个游戏循环:
double t = 0.0;
const double dt = 0.01;
double currentTime = hires_time_in_seconds();
double accumulator = 0.0;
State previous;
State current;
while (!quit)
{
double newTime = time();
double frameTime = newTime - currentTime;
if (frameTime > 0.25)
frameTime = 0.25; // note: max frame time to avoid spiral of death
currentTime = newTime;
accumulator += frameTime;
while (accumulator >= dt)
{
previousState = currentState;
integrate(currentState, t, dt);
t += dt;
accumulator -= dt;
}
const double alpha = accumulator/dt;
State state = currentState*alpha + previousState * (1.0 - alpha);
render(state);
}
提纲是,物理模拟总是喂养的时间(dt
)的数值稳定性同样的增量。为此安排必须考虑到物理和视觉效果可能会以不同的频率更新,并且你不想太落后。
例如,您可能希望以20hz的频率进行更新,但以60hz的帧率进行视觉更新。这个循环做物理线性插值来弥补物理更新和图形更新之间的差异。
此外,当帧之间的时间差远大于dt
时,会出现一个循环来处理分步更新dt
块。关于死亡螺旋的说明只是指您的物理计算根本无法跟上所需更新频率的情况,因此您允许它跳过一些更新。
对于本次讨论,我最感兴趣的部分是安排,以便对物理引擎的呼叫(致电integrate
)始终步进dt
。 reactive-banana是否允许用户编写此样式循环?如果是这样如何?或许一个做实时物理模拟的例子是按顺序(或者已经存在)?
我不确定SDL,但是使用OpenGL和GLFW,它们都在进程的原始线程上使用线程本地存储(它必须是原始线程,供应商限制)。 GHCi默认在不同的线程中运行每个命令。这意味着像OpenGL/GLFW(以及其他几个gui库)的库无法正确访问其线程本地存储并从GHCi进入垃圾箱。解决方法是在启动GHCi时添加-fno-ghci-sandbox。您可以尝试一下,看看它是否可以修复您的SDL + GHCi问题:http://www.haskell.org/ghc/docs/7.0.1/html/users_guide/release-7-0-1.html –
这是一个小问题恐怕比'-fno-ghci-sandbox'更困难。在Mac上,SDL需要进行编译,因为它将'main'重新定义为宏。由于我不了解其他不兼容性,GLFW版本往往会在GHCi中崩溃。 –
如果使用'-fno-ghci-sandbox',GLFW-b不应该从GHCi崩溃。如果确实如此,那么您正在创建一个新的bug,因此请做出报告! :) –