SFML community forums

Help => General => Topic started by: sb on December 11, 2017, 07:39:05 pm

Title: Game Loop Lag
Post by: sb on December 11, 2017, 07:39:05 pm
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
Title: Re: Game Loop Lag
Post by: eXpl0it3r on December 11, 2017, 09:19:49 pm
Does it occur in release mode?
Use a profiler to find the cause.
Title: Re: Game Loop Lag
Post by: sb on December 24, 2017, 12:47:08 pm
Thank you for your answer.
Title: Re: Game Loop Lag
Post by: achpile on December 26, 2017, 09:46:14 pm
probably this


        delay = carry + timer.getElapsedTime().asMilliseconds();
        if(delay >= MSPF) {
            timer.restart();
            while(delay >= MSPF) {
                update();
                delay -= MSPF;
            }
            carry = delay;
        }


just use RenderWindow::setFramerate (or how is it called)
Title: Re: Game Loop Lag
Post by: fallahn on December 26, 2017, 11:28:09 pm
It could well be the effect described here:
http://gameprogrammingpatterns.com/game-loop.html#stuck-in-the-middle

There's no magic bullet as far as I know, and interpolated rendering can be a bit of a pain to set up. Hapax has made a useful library that can help make it less of a chore:
https://github.com/Hapaxia/Kairos
Title: Re: Game Loop Lag
Post by: sb on December 28, 2017, 03:49:28 pm
@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.