带插值的游戏循环 - 奇怪的退一步

时间:2017-09-08 16:20:46

标签: c++ interpolation sfml game-loop

我已经阅读过应用于游戏循环的插值并试图自己实现它。它看起来几乎和我预期的一样,但是当物体结束它的运动时,会发生奇怪的后退。我决定在这里粘贴完整的源码,因为这个问题可能是由一切引起的。

#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();
}

我不知道是什么原因造成这种问题。我期待着你的帮助。

1 个答案:

答案 0 :(得分:0)

您的interpolate功能可以多次计算时间间隔的某些部分。

由于accumulator仅重置每timePerFrame个刻度,因此快速循环速率可以多次添加较小的间隔。如果主循环在0.01秒内运行,则对interpolate的第一次调用在插值因子中使用0.01。下一次,它使用0.02(总计0.03)。这一直持续到updateinterpolate累积足够的时间以使用0.1秒(时间步长)更新位置。由于interpolate在更长的时间内添加,因此对象会跳回来。

now应仅添加当前步骤的时间,而不是完全累积的时间。 (另外,不是调用now来获取每个循环的开始时间,而是将用于结束时间的前一循环{{1}}值用作下一循环的开始时间。否则当你在一个循环的结束和下一个循环的开始之间发生变化时,你会偶尔失去时钟滴答。)