Welcome, Guest. Please login or register.

Login with username, password and session length

 
Advanced search

1411654 Posts in 69395 Topics- by 58451 Members - Latest Member: Monkey Nuts

May 15, 2024, 12:29:47 PM

Need hosting? Check out Digital Ocean
(more details in this thread)
TIGSource ForumsDeveloperTechnical (Moderator: ThemsAllTook)game loops
Pages: [1] 2
Print
Author Topic: game loops  (Read 4188 times)
mechacrash
Level 1
*


It's almost like I'm actually being productive!


View Profile
« on: August 03, 2010, 11:54:43 AM »

I am having alot of problems with game loops. I want to be able to support a user specified FPS however due to rounding and my method of interval calculation, its impossible to use FPS that do not make a whole number when 1000 is divided by them (e.g. 60fps -> 1000 / 60 = 16.66667)

i cant think of any other methods of getting a stable and variable game loop... any suggestions or help?

below is a simple example file... to use it you need to include the winmm library (-lwinmm in G++)

#include <iostream>
#include <windows.h>

using namespace std;

int main(){

timeBeginPeriod(1);
unsigned tick = 0;
unsigned ticka = timeGetTime();
unsigned ms = 0;
unsigned fpscount = 0;
float update = 1000.0 / 50.0; // <- change 50.0 to your desired FPS
while(1){
   ms = timeGetTime();
   if(ms < tick || ms - tick >= (unsigned)update){
      tick = ms;
      fpscount++;
   }
   if((ticka / 1000) != (timeGetTime() / 1000)){
        ticka += 1000;
        cout << fpscount << "\n";
        fpscount = 0;
    }
}
timeEndPeriod(0);
return 0;
}
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #1 on: August 03, 2010, 11:59:30 AM »

On Windows, try using the Sleep function.

My game loop does a Sleep(6); every iteration, which gets me roughly 160 FPS.  You can play with this value to vary the framerate.

Code:
    // Event loop.
    while (true)
    {
        // See if there's a message.
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE))
        {
            // If it's a quit message, bail.
            if (message.message == WM_QUIT)
            {
                break;
            }
           
            // Dispatch the message.
            TranslateMessage(&message);
            DispatchMessage(&message);
        }
        else
        {
            // If there are no messages, call the main game loop.
            MainWindow::CallMainLoop();

            // Sleep for a bit to avoid pegging the processor.
            Sleep(6);
        }
    }
Logged



What would John Carmack do?
increpare
Guest
« Reply #2 on: August 03, 2010, 12:03:24 PM »

Perfectly stable FPS has to be a divisor of monitor refresh-rate (yeah yeah threading I know I know).  So arbitrary ones are going to be impossible anyway.  So don't worry about getting it exact.  
« Last Edit: August 03, 2010, 12:24:22 PM by increpare » Logged
mechacrash
Level 1
*


It's almost like I'm actually being productive!


View Profile
« Reply #3 on: August 03, 2010, 12:18:34 PM »

but then how do people hit 60fps? i sortve made a method of doing it by running it at 16 milliseconds intervals and at every third frame going for a 17 millisecond interval... they evened each other out and gave me a steady 60fps... but it wasnt perfect and it didnt work for other values...

also "average software" i need to attempt to lock it to a specific FPS, hence the stupid function calls... using a sleep timer is quite bad in my case because the FPS would change depending on OS, hardware... etc.

i only use sleep to stop bogging the CPU down... which i didnt put in the example code as im lazy
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #4 on: August 03, 2010, 12:29:18 PM »

but then how do people hit 60fps? i sortve made a method of doing it by running it at 16 milliseconds intervals and at every third frame going for a 17 millisecond interval... they evened each other out and gave me a steady 60fps... but it wasnt perfect and it didnt work for other values...

also "average software" i need to attempt to lock it to a specific FPS, hence the stupid function calls... using a sleep timer is quite bad in my case because the FPS would change depending on OS, hardware... etc.

i only use sleep to stop bogging the CPU down... which i didnt put in the example code as im lazy

60 FPS most likely comes from using vertical sync on a monitor with a 60Hz (or multiple) refresh rate.  Without that, you need to do lots of timer tricks, including timing how long your loop takes to execute and doing delay calculations on the fly.

I've gone down this route before, and came to the conclusion that it simply isn't worth it.  Now I just use sleep functions to hit something around 150 FPS and give the user the option to enable vertical sync.  Delta time takes care of the rest.
Logged



What would John Carmack do?
mechacrash
Level 1
*


It's almost like I'm actually being productive!


View Profile
« Reply #5 on: August 03, 2010, 12:32:30 PM »

so... erm... how do i do Vsync?

also isnt that a fullscreen function only?
Logged

tempestad
Level 0
**


View Profile
« Reply #6 on: August 03, 2010, 12:40:01 PM »

SFML has that built on it, here is that part on the source code:
http://www.sfml-dev.org/documentation/1.6/Window_8cpp-source.htm#l00353

You have to calculate the remaining time to get the frame rate needed, and then wait that time.
The variable myFramerateLimit is the framerate,  in your example. MyClock.Reset() sets the clock to 0, then when you call MyClock.GetElapsedTime() you get the time (in seconds!) from the last Reset().

I think that should be enough to understand how to do it Smiley

Edit: Remember that SFML uses time in seconds with a float type, so if you use milliseconds adapt as necessary.
« Last Edit: August 03, 2010, 12:51:30 PM by tempestad » Logged
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #7 on: August 03, 2010, 01:01:56 PM »

so... erm... how do i do Vsync?

also isnt that a fullscreen function only?

I depends on how you're doing your graphics.  I know how to do it for OpenGL, if you're using DirectX or something else, I can't help you.

And no, it isn't fullscreen only.

For OpenGL on Windows, you need to get a pointer to the wglSwapInterval function, which is an extension, this code will do that:

Code:
// Get the vertical sync extension.
swap_interval = reinterpret_cast<BOOL (APIENTRY*)(int)>(wglGetProcAddress("wglSwapIntervalEXT"));

Once you have the pointer, calling it with a parameter of 0 disables vertical sync, 1 enables it.  Other values may have other effects, but I don't know them.
Logged



What would John Carmack do?
tempestad
Level 0
**


View Profile
« Reply #8 on: August 03, 2010, 01:07:49 PM »

VSync will give you different framerates depending on the refresh rate of the monitor. In this case you would need to apply timing to the gameplay.
Logged
mechacrash
Level 1
*


It's almost like I'm actually being productive!


View Profile
« Reply #9 on: August 03, 2010, 03:46:08 PM »

hmmm... ok... ill look at vsync then

i just originally assumed that vsync was for binding the drawing updates to the refresh rate... wheras my current implementation updates the drawing continuously through the while loop and the 60FPS was meant to be used to update the game logic 60 times a second...

am i on track?
Logged

Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #10 on: August 03, 2010, 04:28:10 PM »

i just originally assumed that vsync was for binding the drawing updates to the refresh rate... wheras my current implementation updates the drawing continuously through the while loop and the 60FPS was meant to be used to update the game logic 60 times a second...

Vsync is for binding to the refresh rate.  My point was that most programs I've seen that peg 60 FPS do it by switching to a 60Hz display mode and using vsync.

Is there any particular reason why you want the player to be able to set the framerate?  Seems like an odd sort of feature.  I think no matter what you do, it's going to be rough estimate.
Logged



What would John Carmack do?
mechacrash
Level 1
*


It's almost like I'm actually being productive!


View Profile
« Reply #11 on: August 03, 2010, 10:08:29 PM »

well im currently developing a small engine for use with a handful of projects i want to persue... so i wanted to make different aspects of the code customisable so i wouldnt have to rewrite code later... FPS was one o fthose things
Logged

BrianSlipBit
Level 1
*



View Profile WWW
« Reply #12 on: August 04, 2010, 05:38:52 AM »

Here are two good links regarding game loop setup:

http://gafferongames.com/game-physics/fix-your-timestep/
http://stackoverflow.com/questions/1823927/simulated-time-in-a-game-loop-using-c

From those you should be able to make the necessary changes to do what you need.  The biggest issue really, is the rate at which you update game logic and how you go about doing that.  The rate at which rendering occurs is less significant, provided it doesn't drop too low.  However, there is little to no benefit trying to render faster than 60Hz.
Logged

dcarrigg
Level 0
***

Software Neurosurgeon


View Profile WWW
« Reply #13 on: August 04, 2010, 08:01:51 PM »

Hey mechacrash,

If you're looking to support any specified framerate, I wouldn't go about it by using vsync. It may work correctly, but not only is vsync something that drivers can override from your application's preference, but you probably dont want to have the rendering portion of your engine in control of how often your game loop is processed.


The first link here is a great article by Glenn Fiedler, but its discussing decoupling physics updates from main game loop updates and doesnt really talk about doing a fixed timestamp for the main game loop. However, the same methodology that he uses to ensure a fixed time stamp for his physics updates, you can use for your main game loop.

Applied to the main game loop, it would follow a pattern like this:
Code:
unsigned int lastTickTime = getTicks(); // This can be whatever high precision timer you are using
unsigned int accumulator = 0;
unsigned int numTicksPerUpdate = 16; // 16 = 1/60fps. 32 = 1/30fps,
while (!done) {
    unsigned int currentTickTime = getTicks();
    unsigned int timePassed = currentTickTime - lastTimeTime;
    lastTickTime = currentTickTime;

    accumulator += timePassed;

    // Now, if your game hitches, if you want it to call multiple updates to make up for the lost time, use this
    while (accumulator > numTicksPerUpdate) {
        accumulator -= numTicksPerUpdate;
        // MAIN GAME LOOP LOGIC
    }

    // Otherwise, when your game hitches, if you want it to call a single update and continue, dropping the missed time, use this
    if (accumulator > numTicksPerUpdate) {
        accumulator = 0;
        // MAIN GAME LOOP LOGIC
    }
}

I just whipped this up right now, but I THINK it should handle whatever update interval you'd like. Let me know if you have any questions.
Logged

Check it out! www.retroaffect.com
deWiTTERS
Level 1
*


deWiTTERS


View Profile WWW
« Reply #14 on: August 05, 2010, 02:33:11 AM »

Some time ago I wrote an article about game loops, so you might find some more info there. It discusses various implementation and their pro's & con's. There is even a lecture video of a guy who used my article as a reference Cool.
Logged

zacaj
Level 3
***


void main()


View Profile WWW
« Reply #15 on: August 05, 2010, 06:15:45 AM »

Code:
int start=clock();
//game stuff
while(clock()-start<CLOCKS_PER_SEC/FPS_DESIRED);
thats a really simple way that seems to work fine, it might be >, not < though
« Last Edit: August 05, 2010, 06:59:14 AM by zacaj » Logged

My twitter: @zacaj_

Quote from: mcc
Well let's just take a look at this "getting started" page and see--
Quote
Download and install cmake
Noooooooo
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #16 on: August 05, 2010, 07:18:13 AM »

Code:
int start=clock();
//game stuff
while(clock()-start<CLOCKS_PER_SEC/FPS_DESIRED);
thats a really simple way that seems to work fine, it might be >, not < though

Except that busy loops like that keep the process running at maximum.  Laptop users especially don't like that, makes CPUs really hot and kills batteries pretty quickly.  Even the fans in my desktop system get really ramped up when I do that.
Logged



What would John Carmack do?
zacaj
Level 3
***


void main()


View Profile WWW
« Reply #17 on: August 05, 2010, 07:43:50 AM »

Yea, and unless theres some c function that takes ms, not seconds like sleep(), that will happen no matter what.  Also, I never had my programs using up all my CPU, and my computer shuts off it its a hot day
Logged

My twitter: @zacaj_

Quote from: mcc
Well let's just take a look at this "getting started" page and see--
Quote
Download and install cmake
Noooooooo
Average Software
Level 10
*****

Fleeing all W'rkncacnter


View Profile WWW
« Reply #18 on: August 05, 2010, 08:00:45 AM »

Yea, and unless theres some c function that takes ms, not seconds like sleep(), that will happen no matter what.

OS APIs typically provide such a function.  Sleep(), (capital S) on Windows, which I pointed out earlier.
Logged



What would John Carmack do?
zacaj
Level 3
***


void main()


View Profile WWW
« Reply #19 on: August 05, 2010, 08:28:26 AM »

nothing cross platform though...
Logged

My twitter: @zacaj_

Quote from: mcc
Well let's just take a look at this "getting started" page and see--
Quote
Download and install cmake
Noooooooo
Pages: [1] 2
Print
Jump to:  

Theme orange-lt created by panic