我的固定时间步长与增量时间和插值的解决方案是错误的吗?

Is my solution to fixed timestep with delta time and interpolation wrong?

本文关键字:解决方案 插值 错误 时间 定时间 我的      更新时间:2023-10-16

我正在尝试编写具有固定增量时间的简单循环,用于物理和插值,然后再渲染状态。我正在固定时间步长的游戏教程中使用 Gaffer,我试图理解它并使其工作。

float timeStep = 0.01;
float alpha = 1.0;
while (isOpen()) {
processInput();
deltaTime = clock.restart(); // get elapsed time
if (deltaTime > 0.25) { deltaTime = 0.25; } // drop frame guard
accumulator += deltaTime;
while (accumulator >= timeStep) {
// spritePosBefore = sprite.getPosition();
accumulator -= timeStep;
// sprite.move(velocity * timeStep, 0);
// spritePosAfter = sprite.getPosition();
}
if (accumulator > timeStep) { alpha = accumulator / timeStep; } else { alpha = 1.0; }
// sprite.setPosition(Vector2f(spritePosBefore * (1 - alpha) + spritePosAfter * alpha));
clear();
draw(sprite);
display();
}

现在,一切看起来都不错。我有固定的物理时间步长,在物理更新后尽可能画画,并在两个位置之间插值。它应该完美无缺,但我仍然可以看到精灵卡顿,甚至偶尔回溯一个像素。为什么会这样?我的代码有问题吗?我花了最后两天的时间试图理解游戏循环,这将确保我完美无瑕的动作,但似乎它不像我想象的那样有效。知道有什么可以改进的吗?

您应该删除 if 语句并始终计算 alpha; if 语句永远不会执行,因为在退出 while 循环后条件始终为 false!

循环后,累加器将介于 0 和 timeStep 之间,因此您最终只需绘制最新位置而不是插值。

我不认为你这样做的方式一定是错误的,但它看起来有点过于复杂。我不完全明白你想做什么,所以我只是要分享我在 SFML 应用程序中实现"固定时间步长"的方式。
以下是最简单的方法,对于大多数应用程序来说"足够好"。不过,这不是最精确的(测量时间和实时时间之间可能会有一点误差(:

sf::Clock clock;    
sf::Event event;
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
if (clock.getElapsedTime().asSeconds() > FLT_FIXED_TIME_STEP) {
clock.restart();
update(FLT_FIXED_TIME_STEP);
}
render();
}

如果你真的需要精度,你可以添加一个浮点变量来充当"缓冲区":

sf::Clock clock;    
sf::Event event;
float timeBeforeNextStep = 0.f; // "buffer"
float timeDilation = 1.f; // Useful if you want to slow or speed up time ( <1 for slowmo, >1 for speedup)
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
timeBeforeNextStep -= clock.restart().asSeconds() * timeDilation;
if (timeBeforeNextStep < FLT_FIXED_TIME_STEP) {
timeBeforeNextStep += FLT_FIXED_TIME_STEP; // '+=', not '=' to make sure we don't lose any time.
update(FLT_FIXED_TIME_STEP);
// Rendering every time you update is not always the best solution, especially if you have a very small time step.
render();
}
}

您可能希望使用另一个缓冲区进行渲染(例如,如果要以正好 60 FPS 的速度运行(。