Hello there.
Does anyone see what mistake I made in my game loop? I thought it to be a standard approach, yet I get a periodic micro-lag roughly every second.
I have already played around with various things like integer positions, sleeping for some milliseconds, enabling v-sync, drawing in a separate thread, interpolating the movement. Yet it must be some different problem as nothing helped so far.
Minimal example (for better readability, all the variables are declared in the beginning):
#include "SFML/Graphics.hpp"
const int FPS = 60; // frames per second
const double SPF = 1.0/FPS; // seconds per frame
const double MSPF = 1000.0/FPS; // milliseconds per frame
bool quit = false; // quit flag
sf::Clock timer; // timer to measure lapsed time
int delay = 0; // delay to determine when to update physics
int carry = 0; // leftover of delay from last update
// object to be drawn
sf::RectangleShape rect = sf::RectangleShape(sf::Vector2f(200, 200));
double rectSpeed = 200;
double x = 0;
// physics update
void update() {
x += rectSpeed*SPF;
while(x > 1200) {
x -= 1400;
}
rect.setPosition(x, 0);
}
// draw to screen
void draw(sf::RenderWindow &window) {
window.clear(sf::Color::Black);
window.draw(rect);
window.display();
}
int main()
{
sf::RenderWindow window(sf::VideoMode(1200, 900), "Test");
//window.setVerticalSyncEnabled(true);
//window.setFramerateLimit(60);
carry = 0;
while(quit == false) {
sf::Event event;
while(window.pollEvent(event)) {
if(event.type == sf::Event::Closed) {
quit = true;
}
}
delay = carry + timer.getElapsedTime().asMilliseconds();
if(delay >= MSPF) {
timer.restart();
while(delay >= MSPF) {
update();
delay -= MSPF;
}
carry = delay;
}
draw(window);
}
window.close();
return 0;
}
Regards,
sb
@achpile: I don't want to tie the game loop updates per second to the graphics.
@ fallahn: Thank you. However, I already implemented interpolation and it works fine.
After trying various things, currently, the problem seems to occur when the window's draw function is blocking the game because it cannot draw instantly, for instance because of vsync.
Currently, I've got the drawing in another thread. However, as I need to synchronize data, the drawing thread locks a mutex and the game loop can't advance. I think that a solution is for the mutex to be only locked when the window ACTUALLY draws and not just has to wait for the next time to draw. However, it appears to be that this is not possible with setVerticalSyncEnabled or setFrameLimit.
//drawing thread
mutex.lock();
window.clear();
window.draw(*GAME); // << this method waits for the vysnc or whatever before drawing and thus the mutex is locked for longer than necessary, causing a delay in the game update loop
window.display();
mutex.unlock();
EDIT: Wait, I made a mistake. It should be the display that causes the lag. I will try locking the mutex only around .draw but not .display.