Игровой цикл с интерполяцией - странный шаг назад

Я прочитал об интерполяции, примененной к игровым циклам, и попытался реализовать ее самостоятельно. Это выглядит почти так же, как я ожидал, но когда объект заканчивается, его движение делает странный шаг назад. Я решил вставить сюда полный исходный код, потому что эта проблема может быть вызвана всем.

#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 ответ

Ваш interpolate Функция может рассчитывать некоторые части временного интервала несколько раз.

поскольку accumulator только сбрасывает каждый timePerFrame тики, высокая скорость цикла может добавить меньшие интервалы несколько раз. Если основной цикл выполняется за 0,01 секунды, первый вызов interpolate использует это 0,01 в коэффициент интерполяции. В следующий раз он использует 0,02 (для общего добавления 0,03). Это продолжается до тех пор, пока не будет накоплено достаточно времени для update обновить позицию, используя 0,1 секунды (шаг по времени). поскольку interpolate добавленный в течение большего времени, объект возвращается назад.

interpolate следует добавлять только время текущего шага, а не полностью накопленное время. (Также вместо звонка now чтобы получить время начала каждого цикла, предыдущий цикл now значение, используемое для времени окончания, должно использоваться в качестве времени начала следующего цикла. В противном случае вы потеряете время от времени, когда оно меняется между концом одного цикла и началом следующего.)

Другие вопросы по тегам