Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Game Loop Lag  (Read 4427 times)

0 Members and 1 Guest are viewing this topic.

sb

  • Newbie
  • *
  • Posts: 22
    • View Profile
Game Loop Lag
« 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

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11033
    • View Profile
    • development blog
    • Email
Re: Game Loop Lag
« Reply #1 on: December 11, 2017, 09:19:49 pm »
Does it occur in release mode?
Use a profiler to find the cause.
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

sb

  • Newbie
  • *
  • Posts: 22
    • View Profile
Re: Game Loop Lag
« Reply #2 on: December 24, 2017, 12:47:08 pm »
Thank you for your answer.

achpile

  • Full Member
  • ***
  • Posts: 231
    • View Profile
    • Achpile's homepage
    • Email
Re: Game Loop Lag
« Reply #3 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)

fallahn

  • Hero Member
  • *****
  • Posts: 507
  • Buns.
    • View Profile
    • Trederia
Re: Game Loop Lag
« Reply #4 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

sb

  • Newbie
  • *
  • Posts: 22
    • View Profile
Re: Game Loop Lag
« Reply #5 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.
« Last Edit: December 28, 2017, 03:58:43 pm by sb »