Fixed Timestep creates a reliable and regular update for physics and logic. It doesn't, however, fix the refresh rate of the window. This is decided by the OS; if it would prefer to do something else, your window will have to wait.
Therefore, each frame shown isn't guaranteed to be perfectly regular and, in some cases, not at the exact time you expect a frame - it could be part way.
Frame interpolation can help solve this visual artifact. It's the very last part in the Fix Your Timestep article. I commented about this here recently and there is a small accompanying video to that comment showing the difference. See the comment here (also includes a link to Fix Your Timestep article).
I looked at your video and it appears the same issue is happening with me so I implemented interpolation but unfortunately the issue is still there. Here is a minimal code example which is also on
github:
main.cpp
#include "State.h"
int main()
{
sf::RenderWindow window(sf::VideoMode(1500, 1000), "Timestep Testing");
window.setKeyRepeatEnabled(false);
State state;
sf::Clock clock;
float dt = 1.0f / 60.0f;
float accumulator = 0.0f;
while(window.isOpen())
{
sf::Event event;
while(window.pollEvent(event))
if(event.type == sf::Event::Closed)
window.close();
accumulator += clock.restart().asSeconds();
while(accumulator >= dt)
{
state.update(dt);
accumulator -= dt;
}
float interp = accumulator / dt;
window.clear();
state.draw(window, interp);
window.display();
}
return 0;
}
State.h
#pragma once
#include "SFML\Window.hpp"
#include "SFML\Graphics.hpp"
class State
{
public:
State();
void update(float timeStep);
void draw(sf::RenderWindow& window, float interp);
private:
sf::RectangleShape rect;
sf::Font font;
sf::Text fps;
sf::Text dps;
sf::Clock clockUpdate;
sf::Clock clockDraw;
int frames;
int draws;
sf::Vector2f pos;
sf::Vector2f lastPos;
};
State.cpp
#include "State.h"
State::State() : rect(sf::Vector2f(100.0f, 100.0f))
{
font.loadFromFile("lucon.ttf");
fps.setFont(font);
dps.setFont(font);
fps.setPosition(10.0f, 0.0f);
dps.setPosition(10.0f, 30.0f);
frames = -1;
draws = -1;
}
void State::update(float timeStep)
{
if(clockUpdate.getElapsedTime().asSeconds() >= 1.0f) {
fps.setString("FPS: " + std::to_string(frames));
frames = 0;
clockUpdate.restart();
}
frames++;
sf::Vector2f d;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::W))
d.y = -1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::S))
d.y = 1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::A))
d.x = -1;
if(sf::Keyboard::isKeyPressed(sf::Keyboard::Key::D))
d.x = 1;
lastPos = pos;
pos += 150.0f * d * timeStep;
rect.setPosition(pos);
}
void State::draw(sf::RenderWindow& window, float interp)
{
if(clockDraw.getElapsedTime().asSeconds() >= 1.0f) {
dps.setString("Draw Calls: " + std::to_string(draws));
draws = 0;
clockDraw.restart();
}
draws++;
window.draw(fps);
window.draw(dps);
sf::Vector2f posInterp = pos * interp + lastPos * (1.0f - interp);
rect.setPosition(posInterp);
window.draw(rect);
}
I'm getting a solid 60 frames per second and around 800 draw calls per second but the movement is still noticeably jittery. I also noticed that if I comment out the following code from
main.cpp the issue goes away and the movement is buttery smooth.
sf::Event event;
while(window.pollEvent(event))
if(event.type == sf::Event::Closed)
window.close();
It appears that calling
window.pollEvent() is causing the movement to be jittery.