libgdx - 带插值的固定时间步长 - 没有 box2d

libgdx - fixed timestep with interpolation - without box2d

我在游戏中使用图形插值实现固定时间步时遇到了一些问题。

这是渲染方法的一部分:

@Override
public void render(float delta)
{
    double newTime = TimeUtils.millis() / 1000.0;
    double frameTime = Math.min(newTime - currentTime, 0.25);

    accumulator += frameTime;
    currentTime = newTime;

    while (accumulator >= step)
    {
        updateObjects(step);
        accumulator -= step;
    }

    double alpha = accumulator / step;

    interpolateObjects((float)alpha);
}

这是更新对象:

for (int i = 0; i < world.level.gameObjects.size(); i++)
{
    GameObject go = world.level.gameObjects.get(i);
    go.prevPosition.set(go.position);//save previous position
    go.update(delta);
}

插值对象:

for (int i = 0; i < world.level.gameObjects.size(); i++)
{
    GameObject go = world.level.gameObjects.get(i);
    go.position.lerp(go.prevPosition, alpha);
}

然后使用位置

渲染对象

据我所知这应该有效,但它没有。 在高 fps (200-400) 上,一切都太慢了,甚至看不到运动,我只能看到位置正在改变 0.0001 或类似的东西

在低 fps (10-20) 下,移动是可见的,但对象再次非常慢...

如果我禁用插值,那么一切都会正常工作(在任何 fps 上),但是一切都会变得紧张。

所以问题出在插值的某个地方。

您的插值 go.position.lerp(go.prevPosition, alpha) 设置为假设 prevPosition 最后一次更新为 step 的精确倍数,但是当您像这样更新 prevPositiongo.prevPosition.set(go.position) 你在框架的第一次更新时破坏了那个合同。看起来您也在向后移动(从位置到之前的位置)。

我认为您需要第三个向量,这样可以保证最后一个插值不会影响您的固定时间更新。在这里我将其称为interpPosition,它将用于绘图而不是position

您实际上在技术上似乎是在外推(而不是内插)该值,因为您没有提前更新并且您的 alpha 是根据累加器中剩余的时间计算的。如果你想从计算的最后两个位置进行线性外推,你可以这样做(注意外推的1+alpha):

for (int i = 0; i < world.level.gameObjects.size(); i++)
{
    GameObject go = world.level.gameObjects.get(i);
    interpPosition.set(go.prevPosition).lerp(go.position, 1 + alpha);
}

根据您的模拟速度(以及物体加速的速度),这可能看起来仍然不稳定。我认为一种更流畅但计算速度较慢的方法是使用 alpha 而不是步长时间进行完全计算的更新,并将其存储在 interpPosition 向量中。但只有在必要时才这样做。