0
\$\begingroup\$

I've been building an SFML engine and I've been very confused on the FPS, frame independent movement and game loop.

My particular problem is that I have a variable set to 60 for the frame limit but changing this value doesn't seem to change the frame limit. I used the built in SFML window function to set a limit and it seems to work.

Am I doing something wrong with this loop?

while (mWindow.isOpen())
{
    time=renderClock.getElapsedTime();
    float fFps=1000000/time.asMicroseconds();
    std::stringstream s;
    s<<fFps<<" fps";
    fps.setString(s.str());
    renderClock.restart();

    const sf::Int64 frameTime = 1000000/FRAMES_PER_SECOND;
    sf::Clock c;
    sf::Time t=c.getElapsedTime();
    sf::Int64 nextFrameTime=t.asMicroseconds()+frameTime;

    int loops = 0;
    while( t.asMicroseconds() < nextFrameTime && loops < MAX_FRAMESKIP)
    {
        processEvents();
        updateTime=updateClock.restart().asMilliseconds();
        update(updateTime);
        t=c.getElapsedTime();
        loops++;
    }

    render();
}

Here's a link to my full code: https://github.com/csharpest94/SFML/blob/master/src/Game.cpp

\$\endgroup\$
2
  • \$\begingroup\$ Can you check if you leave the second while loop because of t.asMicroseconds() < nextFrameTime or loops < MAX_FRAMESKIP, please ? You probably reach MAX_FRAMESKIP very fast if it is set to 10. \$\endgroup\$
    – Heckel
    Apr 1, 2015 at 14:21
  • \$\begingroup\$ yeah I tried changing the values of MAX_FRAMESKIP to a few different values and it didn't effect it. Also in debugging the value of t.asMicroseconds() came to about 54719757 and loops was equal to 1 \$\endgroup\$
    – Csharpest
    Apr 1, 2015 at 15:21

3 Answers 3

0
\$\begingroup\$

This might not be a solution to problem , but as far as I know main game loop should not be limited using sf::Window::setFramerateLimit(unsigned int limit). Only game logic, AI, physics should be limited, events should be processed without any limitation as not to create input lag.

I would suggest:

sf::Clock clock;
sf::Time accumulator = sf::Time::Zero;
sf::Time ups = sf::seconds(1.f / 60.f);

while (windows.isOpen())
{
    ProcessEvents();

    while (accumulator > ups)
    {
        accumulator -= ups;
        UpdateLogic();
        //AI();
        //Physics();
    }

    Render();
    accumulator += clock.restart();
}

Smooth movement can be easily implemented because logic runs at 60 updates per second, so if you want for instance sprite to move about 100px you need to divide this by 60 or in example above multiply with ups variable:

//pseudo code sprite.move(100 * ups); So every update your sprite will move for the same distance.

With this approach comes the danger that if you're not limiting game loop, your CPU will be working at high load, even if it's unnecessary. Unfortunately way to prevent this situation requires more complex game loops. Of course you can limit your render analogously and set it to be running at for example 100 frames per second, however that is not the best idea since there might be some issues if render can't keep up with fps - whole loop will be blocked.

I suggest you take a look at diagrams and descriptions in this article: http://entropyinteractive.com/2011/02/game-engine-design-the-game-loop/

About your problem, you can try implementing fixed time step loop I mentioned above with limiting main loop through sf::Window::setFramerateLimit(unsigned int limit).

\$\endgroup\$
0
\$\begingroup\$

Why not just use the sf::Window::setFramerateLimit(unsigned int limit) method? That should be a lot more straightforward and it works flawlessly for me.

EDIT:Just read you used it before. Gonna tell you something. Basic of rule of programmers. If it works, don't fix it.

\$\endgroup\$
4
  • \$\begingroup\$ But doesn't using the setFrameLimit method still leave a problem of frame dependant movement? :s Thats why I tried the loop in the first place \$\endgroup\$
    – Csharpest
    Apr 1, 2015 at 15:09
  • \$\begingroup\$ @Csharpest What problem does it leave? By coding the loop you are basically doing the same thing that method does. Limiting the framerate. \$\endgroup\$ Apr 1, 2015 at 15:14
  • \$\begingroup\$ Look at the code, he limits the framerate but not the rate at which the events are handled. \$\endgroup\$
    – Heckel
    Apr 1, 2015 at 15:24
  • \$\begingroup\$ @Heckel Well, I guess you are right, but the only thing SFML really does is after the display function is called it waits a bit to counter the framelimit. That's it really. So it shouldn't have any thing to do with how fast or how many times the events are handled per second. \$\endgroup\$ Apr 1, 2015 at 15:34
0
\$\begingroup\$

Your issue here is not that you are not using sf::Window::setFramerateLimit(unsigned int limit), but that you are only actually calculating your frameTime variable once, as it is really a constant.

All that you have to do is change:

const sf::Int64 frameTime = 1000000/FRAMES_PER_SECOND;

to:

sf::Int64 frameTime = 1000000/FRAMES_PER_SECOND;

and that should fix the issue since the frameTime will now be calculated once every loop.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .