我已经阅读过应用于游戏循环的插值并试图自己实现它。它看起来几乎和我预期的一样,但是当物体结束它的运动时,会发生奇怪的后退。我决定在这里粘贴完整的源码,因为这个问题可能是由一切引起的。
#include <SFML/Graphics.hpp>
#include <chrono>
sf::RenderWindow window(sf::VideoMode(800, 600), "Interpolation");
sf::Event event;
int fps = 10; // set to 10 for testing purpose
std::chrono::nanoseconds timePerFrame = std::chrono::seconds(1);
std::chrono::nanoseconds accumulator;
std::chrono::steady_clock::time_point start;
sf::RectangleShape shape1(sf::Vector2f(50, 50));
sf::RectangleShape shape2(sf::Vector2f(50, 50));
sf::Vector2f movement(0, 0);
sf::Vector2f position1(375, 100);
sf::Vector2f position2(375, 275);
void initialization();
void processInput();
void update();
void interpolate();
void render();
int main()
{
initialization();
while(window.isOpen())
{
start = std::chrono::steady_clock::now();
processInput();
while(accumulator >= timePerFrame)
{
update();
accumulator -= timePerFrame;
}
interpolate();
render();
accumulator += std::chrono::steady_clock::now() - start;
}
return 0;
}
void initialization()
{
timePerFrame /= fps;
shape1.setPosition(position1);
shape2.setPosition(position2);
}
void processInput()
{
while(window.pollEvent(event))
{
if(event.type == sf::Event::Closed) window.close();
}
}
void update()
{
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left)) movement = sf::Vector2f(-300, 0);
else if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right)) movement = sf::Vector2f(300, 0);
else movement = sf::Vector2f(0, 0);
position1.x += movement.x / fps;
position2.x += movement.x / fps;
shape1.setPosition(position1);
shape2.setPosition(position2);
}
void interpolate()
{
double interpolationFactor = (double) accumulator.count() / timePerFrame.count();
shape2.setPosition(position2.x + (movement.x / fps * interpolationFactor), position2.y);
}
void render()
{
window.clear(sf::Color::Black);
window.draw(shape1);
window.draw(shape2);
window.display();
}
我不知道是什么原因造成这种问题。我期待着你的帮助。
答案 0 :(得分:0)
您的interpolate
功能可以多次计算时间间隔的某些部分。
由于accumulator
仅重置每timePerFrame
个刻度,因此快速循环速率可以多次添加较小的间隔。如果主循环在0.01秒内运行,则对interpolate
的第一次调用在插值因子中使用0.01。下一次,它使用0.02(总计0.03)。这一直持续到update
为interpolate
累积足够的时间以使用0.1秒(时间步长)更新位置。由于interpolate
在更长的时间内添加,因此对象会跳回来。
now
应仅添加当前步骤的时间,而不是完全累积的时间。 (另外,不是调用now
来获取每个循环的开始时间,而是将用于结束时间的前一循环{{1}}值用作下一循环的开始时间。否则当你在一个循环的结束和下一个循环的开始之间发生变化时,你会偶尔失去时钟滴答。)