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
的精确倍数,但是当您像这样更新 prevPosition
时 go.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
向量中。但只有在必要时才这样做。
我在游戏中使用图形插值实现固定时间步时遇到了一些问题。
这是渲染方法的一部分:
@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
的精确倍数,但是当您像这样更新 prevPosition
时 go.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
向量中。但只有在必要时才这样做。