Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better game loops than endless loop + block?

Every game tutorial and game framework (even the rather new XNA framework) start off with a never ending loop that has an equivalent of DoEvents() to prevent the OS from locking up.

Comming from a non-game based perspective I feel this kind of code smells rather funky.
Are there no better alternatives?

--EDIT--
A lot of answers say every program is basically a loop. True, but I feel the loop should be performed by your OS, not by you. Only the OS has all the information it needs to distribute its resources in an optimal way. Or am I missing an important point here?

like image 716
Boris Callens Avatar asked Mar 25 '09 09:03

Boris Callens


3 Answers

Every Windows app has at its core a loop that looks something like this:

BOOL bRet;

while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0 ) 
{
   if (bRet == -1 )
   {
      // handle the error and possibly exit
   }
   else
   {
      TranslateMessage( &msg );
      DispatchMessage( &msg );
   }
}

It's the application's job--not the operating system's--to ensure that messages are dispatched.

As you probably know, early Windows games used an alternate method where, instead of calling the blocking GetMessage function, they'd call PeekMessage, and then call the game's main processing loop if there was no message to handle. Various forms of delays were used to try to get an adequate frame rate without taking 100% CPU. There just wasn't a good enough timer to give a smooth frame rate.

Today, it might not be necessary to explicitly write a loop that calls DoEvents. It might be possible now to get a smooth frame rate by using the built-in timer pool timers (exposed in .NET by System.Threading.Timer, and wrapped by System.Timers.Timer).

As I recall, there were also issues with getting mouse and keyboard events in a timely manner. We used direct keyboard and mouse access rather than depending on the message loop, because the message loop was often too slow and sometimes would cause us to lose information.

I've not written games in a number of years, and I don't know what .NET is like as a games platform. It's possible that input is still a problem--that the message queue simply isn't fast enough to give the lightning-quick response that game developers want. So they bypass the message queue for critical tasks.

like image 114
Jim Mischel Avatar answered Sep 28 '22 09:09

Jim Mischel


Games (in most cases) are simulations. Traditionally this means you update the simulation, present its current state (eg. render graphics), and repeat. The natural representation for this is a loop.

The Win32 message pump on the other hand is a platform specific quirk, geared towards the event-driven applications that make up the majority of apps on Windows. It's by no means the standard for applications across all platforms so it's not surprising that not all software fits nicely into the model. So to amend a typical program to fit the Win32 model, you typically drain that queue in one go, once per iteration of the loop, using PeekMessage until it's empty. Or, you put that logic into a separate thread and use GetMessage as appropriate.

For most games with performance in mind there is no other practical way to do this. Firstly, if you tried to make the game event-driven instead of polled you'd need higher resolution timing than Windows can reliably give you if you want to keep the high performance that many games go for. Secondly, Windows is only one of the platforms that games are written for, and reworking the game to fit nicely into the Win32 model will just be an inconvenience for dedicated game platforms which expect the canonical game loop instead.

Finally, concerns about 'taking 100% CPU' are misplaced. Most modern games are designed to be used in fullscreen mode with exclusive hardware access, not to be just one of several other applications co-existing. Customers of such games actually demand that the game makes the most use of their hardware and this cannot be done if there are deliberate Sleep() calls or updates are dependent on external timers waking the application N times a second. Obviously there are exceptions for many games, eg. those that are designed to run primarily in a window, but it's important to note the distinction.

like image 38
Kylotan Avatar answered Sep 28 '22 07:09

Kylotan


All programs that are running are never ending loops. Though in some cases you don't interact with the loop (like in web programming or other minor programs)

Your OS is a loop waiting for input commands. Same with a game. A web server is a loop waiting for requests.

A great explanation is from the user slim on one of my own questions.

like image 44
Ólafur Waage Avatar answered Sep 28 '22 07:09

Ólafur Waage