Jump to content

C++ timing the update function

Nineshadow

As you may know, most games lock their update function to only be called at 60 times a second (or something else like that), which is always a good practice.

 

But how is it implemented?

I know the logic behind it, kind of.

 

I have a global variable which I initialize with GetTickCount(). This function returns the amount of ticks the CPU has gone through since it was booted up.Let's call this variable "last".

Then, before calling the update function, I store into another variable, "now", GetTickCount() again. 

 

In another variable, "delta", I store the difference between "now" and "last".

 

If the difference is bigger than a certain number(for my case it works pretty well with 720), then I update "last" with a new GetTickCount() and substract 720 from delta.

 

Then I go ahead and call update().

 

This works fairly well, but if I add the render function in there too, it stops working (for obvious reasons), that's because this way of doing it isn't that good.The amount of ticks a second a CPU does varies greatly and how much each function being called also varies so...not a good practice.

 

What a good practice would be is to do pretty much the same thing, but with system time in something like nanoseconds.Then I transform the amount of nanoseconds into ticks, and if the amount of ticks that have passed is bigger than a number, I do the same thing.

 

Is there any function that returns the System time in nanoseconds?

Or any other better solution?

Sleeping for a short amount before calling the update function also works but...no,just no. Bad practice.

i5 4670k @ 4.2GHz (Coolermaster Hyper 212 Evo); ASrock Z87 EXTREME4; 8GB Kingston HyperX Beast DDR3 RAM @ 2133MHz; Asus DirectCU GTX 560; Super Flower Golden King 550 Platinum PSU;1TB Seagate Barracuda;Corsair 200r case. 

Link to comment
Share on other sites

Link to post
Share on other sites

C++? use STL's chrono to set up a timer class with microsecond precision.

Then you can simply grab microseconds, divide by 1000 and you get milliseconds passed, in floating point precision, allowing checks vs 16.66667 ms passed

Link to comment
Share on other sites

Link to post
Share on other sites

On Windows your best option for timing will be to create a class that uses QueryPerformanceCounter/QueryPerformanceFrequency. 

 

As for the game loop, here's the code I've used for my last few games that you could take a look at.

 

All of your updating, rendering, networking etc would be done in the update function.

 

If you'd like to see my Clock class I can post that as well.

void FizzleEngine::start(){	running = true;	Clock frameTimer;	Clock fpsClock;	float timeForFrame;	U64 frameCount = 0;	fpsClock.update();	while(running && window->isRunning())	{		frameTimer.update();		float dt = clock.update(); //time since last frame in seconds		update(dt);		if(game->getTargetFPS() > 0) //if the game is locked to some FPS		{			timeForFrame = frameTimer.update();			float timePerFrame = 1.0f / game->getTargetFPS();			float diff = timePerFrame - timeForFrame; //remaining time in frame			if(diff > 0)			{				Sleep((DWORD)(900 * diff)); //sleep for 90% of the time left in frame			}			while(diff > 0) //spin for the remaining 10%			{				timeForFrame += frameTimer.update();				diff = timePerFrame - timeForFrame;			}		}                //calculate current framerate		if(frameCount % 10 == 0)		{			dt = fpsClock.update();			currentFPS = 10 / dt;		}				frameCount++;	}	game->onExit();}

1474412270.2748842

Link to comment
Share on other sites

Link to post
Share on other sites

void FizzleEngine::start(){	running = true;	Clock frameTimer;	Clock fpsClock;	float timeForFrame;	U64 frameCount = 0;	fpsClock.update();	while(running && window->isRunning())	{		frameTimer.update();		float dt = clock.update(); //time since last frame in seconds		update(dt);		if(game->getTargetFPS() > 0) //if the game is locked to some FPS		{			timeForFrame = frameTimer.update();			float timePerFrame = 1.0f / game->getTargetFPS();			float diff = timePerFrame - timeForFrame; //remaining time in frame			if(diff > 0)			{				Sleep((DWORD)(900 * diff)); //sleep for 90% of the time left in frame			}			while(diff > 0) //spin for the remaining 10%			{				timeForFrame += frameTimer.update();				diff = timePerFrame - timeForFrame;			}		}                //calculate current framerate		if(frameCount % 10 == 0)		{			dt = fpsClock.update();			currentFPS = 10 / dt;		}				frameCount++;	}	game->onExit();}

What's the point of Sleep? Which by the way is not accurate at all and shouldnt be used ?

Link to comment
Share on other sites

Link to post
Share on other sites

What's the point of Sleep? Which by the way is not accurate at all and shouldnt be used ?

So that the CPU isn't pinned to 100% at all time if it doesn't have to be. As for its accuracy, that's why you only sleep for a percentage of the time. At 90% sleep time I've found zero difference between using sleep and spinning the entire time.

1474412270.2748842

Link to comment
Share on other sites

Link to post
Share on other sites

So that the CPU isn't pinned to 100% at all time if it doesn't have to be. As for its accuracy, that's why you only sleep for a percentage of the time. At 90% sleep time I've found zero difference between using sleep and spinning the entire time.

interesting finding, I've been told to avoid sleep in performance-sensitive application like games because it doesn't provide any insurance in terms of precision. And due to the nature of a game as application type (usually fullscreen and being the main resource-chewing program), a cpu-burning loop is what's recommended for max accuracy.

http://gamedev.stackexchange.com/questions/25354/make-the-game-run-60-fps-in-irrlicht-engine/ 

But I see how yours seem to work fine, I wonder if you could implement a flexible loop that utilized the idle time to optimize for further frames (as mentioned in the link above, resource updating etc).

Link to comment
Share on other sites

Link to post
Share on other sites

But I see how yours seem to work fine, I wonder if you could implement a flexible loop that utilized the idle time to optimize for further frames (as mentioned in the link above, resource updating etc).

That's definitely possible but really for a finished game I would never lock the fps, I just have it there so while developing the game doesn't have to run at 30,000 fps which can cause problems for things like physics.

 

However there are games like Diablo 3 that allow the user to set the max framerate and if the user is setting an option like that it's because they don't want to max out the cpu so I think sleeping is the better option there.

 

Also this all only matters if you allow the user to disable vsync, if not, that will take care of all the fps limiting for you.

1474412270.2748842

Link to comment
Share on other sites

Link to post
Share on other sites

okay, first of all, don't use GetTickCount(), it's not very precise. If you're on windows use QueryPerformanceCounter and QueryPerformanceFrequencey, or if you have C++11 use the new <chrono> header file from STL to get timings.
Second of all, don't use sleep, it is anything but precise. If you really have to use it make sure you want to sleep for example 1 second, you multiply it by something like 0.8 or 0.9 so the chance of it overshooting is minimized. It is better to just have the rendering loop running at the highest speed possible, and then interpolate the objects to smooth their positions.

This article describes pretty well how to fix your timestep: http://gafferongames.com/game-physics/fix-your-timestep/

Link to comment
Share on other sites

Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×