views:

952

answers:

8

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?

+1  A: 

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.

Ólafur Waage
You are basically right, although this is only true for GUI-based programs. for trivial and command line applications you can easily get away without a main loop.
Adrian Grigore
Added a clarification.
Ólafur Waage
Read your post and indeed I figured that. But since the OS is already doing this loop, is it not a good idea to hook into that loop (use the OS's events) rathern then create our own loop in the OS loop?
borisCallens
A: 

Message Queues are Infinite loops as well which makes all the programs as Infinite Loops.

Aamir
A: 

if you not feel comfortable about it, package it with class and interface,

that is what we say "open and close principle": open the interface never changed, close the dirty part.

why we use loop? because it is the basic structure of our computer!

linjunhalida
I fear there is a miscommunication. I know how I could hide all the ugly bits, but the question is why should we implement a loop within the OS loop.
borisCallens
+1  A: 

The better loop is an endless loop with blocking call to dispatch events/messages. If there's nothing to be done, you should indeed not sleep, but block while waiting for the OS. But if the OS indeed doesn't block when you poll for events, sleeping between polling is the only solution to prevent 100% CPU use.

MSalters
Ok, that's actually what I meant with sleep. (the old DoEvents). Will change post to reflect that.
borisCallens
+1  A: 

I don't see how it could be done much differently?

Your program execution happens inside a thread (or multiple threads if you're fancy). Having a gameloop (or a win32 GetMessage/DispatchMessage pump) is all about waiting for event to happen and then handle them. The alternative would be registering callbacks, then calling an HandleAllMyMessages(), which would internally do pretty much the same thing... and that wouldn't really buy you anything.

The OS isn't going to be able to magically split your program into multiple threads, since it has no knowledge of what you want to do within those threads. Spawning a new thread for every incoming message would be both performance and synchronization hell.

snemarch
+4  A: 

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.

Jim Mischel
I was actually thinking if it would make sence to make a timer that knows the frequency of the screen to create frames. In that way on unnecessary runs ever get made.Also the idea coined by @Bryan Parker to have the drawing in a separate thread to pull it loose from the rest(game logic/IO)...
borisCallens
..sounds like a nice idea. I don't know if it is pratical though.
borisCallens
Most games have rendering in a separate thread now. And you want to be able to decouple your updates from vsync for performance testing (among other reasons)
BigSandwich
You don't want your game updates to be dependent on screen refresh rate - game logic should run on predictable wall-time, decoupled from screen painting.
snemarch
Yes, I agree, but most game engines today have the screen refresh rate and the game logic tied up, that's why you have to multiply your velocities by Timer.timerDelta or something like that.
Seth Illgard
A: 

On Win32 I use a MultiMedia timer to call my gamelogic tick...

// request 1ms period for timer
g_mmTimer = timeBeginPeriod(1); 
if (g_mmTimer != TIMERR_NOERROR)
 return false;

//start game loop event timer/thread
g_mmTimer = timeSetEvent(10, 10, DoUpdate, 0, TIME_PERIODIC );

Optionally, you can do all the drawing in another thread so that the game logic is automatically independent of frame rate.

Bryan
+1  A: 

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.

Kylotan