Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have seen different "basic" game loops both from books like "Introduction to 3D game programming with DX11" or online tutorial ( Rastertek ) and if we take off all the fancy stuff to control framerate and more they all look roughly like this :

while (msg != WM_QUIT) // 
{
    if (PeekMessage(&msg,0,0,0,PM_REMOVE)
    {
        // Translate and dispatch message
    }
    else
    {
        // Do update, rendering and all the real game loop stuff
    }
}

If you run it this way it works perfectly, but the thing that i do not understand is the else. If i look naively at the loop i might think that if the system keeps sending events ( key presses, mouse clicks and more ) the else part will never be executed, am i wrong ? ( yes!! i am but this is exactly the point, i don't understand why! ).

I'd like to understand why the loop works this way. If the messages were strictly related to the window ( resizing,moving,closing ) i'd understand it, but they are not. Let's say that i keep pressing any key a WM_KEYDOWN message is repeatedly sent and a message is peeked, thus never allowing the else part to execute

I have not a lot of experience with the Win32 library and i'm probably missing something^^.

Thank you for your time and happy coding!

share|improve this question
add comment

3 Answers 3

I have not seen an else being used in this instance (the Rastertek tutorial you mentioned does not use an else).

My guess would be if that you tried to resize your window the game rendering would freeze proving that the else part is never executed, as the resize message would be constantly sent.

A common loop would have this structure.

while (true) 
{
    while (PeekMessage(&msg,0,0,0,PM_REMOVE)
    {
        // Translate and dispatch message
    }

    if (msg.message == WM_QUIT)
    {
        break;
    }

   // Do update, rendering and all the real game loop stuff

}
share|improve this answer
    
yes sorry, my fault, Rasterek tutorial does exactly as you say. But the code sample i provided is used in "Beginning 3D Game programming with DX11" –  Edoardo Tyger Dominici Jul 28 '13 at 18:49
2  
Avoiding the else can cause problems, by delaying important windows messages like the ones for mouse or keyboard input. If you get two key down messages in one frame you probably want to process them both before rendering it for example. –  Adam Jul 28 '13 at 20:03
    
Yes sorry, it was supposed to be while. –  Syntac Jul 28 '13 at 20:09
    
A bit off topic here but I'm assuming that in the example above the msg-declaration is missing inside the while(true) statement correct? If that is not the case, the if statement will fail if there are two or more messages and the WM_QUIT message isn't last one in the queue. –  Aaron Kabashi Jul 30 '13 at 16:44
    
PeekMessage will only ever return WM_QUIT once the message queue is empty therefore guaranteeing that the last message is in fact WM_QUIT. msdn.microsoft.com/en-us/library/windows/desktop/… –  Syntac Jul 30 '13 at 23:54
add comment

I think the thing you need to grasp is that the message processing will run much faster than the rate at which messages are sent.

For the example code you've provided, here's an estimate of timings:

while (msg != WM_QUIT) // 
{
    if (PeekMessage(&msg,0,0,0,PM_REMOVE)
    {
        // Translate and dispatch message
        // [A] --> This takes a very small amount of time (epsilon ms)
    }
    else
    {
        // Do update, rendering and all the real game loop stuff
        // [B] --> This takes way more time, ~16 ms at 60 fps for instance
    }
}

I've not searched the documentation for this but Windows is probably not spamming messages all the time: they have to come at regular intervals or they'd be clobbering the system. Maybe they use the keyboard refresh rate if you keep pressing one key. Maybe they use the screen refresh rate.

Let's say a new message comes every t ms, reasonably greater than epsilon. The [A] part of the loop will process all stacked messages very quickly: it will run for epsilon ms and start again, which leaves no chance for new messages to arrive. As soon as all messages are consumed, the [B] part will run and new messages will stack again.

Here's an illustration to try to make my point, [An] are processings of the [Mn] messages sent by Windows, and [Bn] are actual frame updates:

Game:    --[A1][B1----------][A2][A3][A4][B2----------][A5][A6][A7][B3------->

            ^       ^       ^       ^       ^       ^       ^      ^      
Windows: ..[M1]....[M2]....[M3]....[M4]....[M5]....[M6]....[M7]....[M8]....

Here you can see that as long the duration of [A] stays reasonably small compared to the message rate (it's already very exaggerated here), the game will still have plenty of time to update its frames.

So this explains why such a game loop structure doesn't prevent a game to run normally. But the solution CoderScott proposed in his answer makes this execution flow much more explicit, so in my opinion it should be preferred.

share|improve this answer
add comment

if/else in your loop will process windows messages before anything. It will not block loop too long (of course if your WndProc will be good). Usually there is not so much messages. I dont think there is a better way to prevent window from stop responding and save FPS. If you will keep your message processing code good i think your loop will be great.

Here is my code, i believe it will be interesting for you, and it is quite usable. But one day i will code a new one. At least it is much better than many other. For playable game you will definitely need a stable state update() rate. Windows messages will not break it.

// Game loop paramters.
const int TICKS_PER_SECOND = 70; // Update() rate per second
const int SKIP_TICKS = 1000 / TICKS_PER_SECOND;
const int MAX_FRAMESKIP = 10;

Run() function:

DWORD next_game_tick = GetTickCount();
int loops;
MSG msg = {0};
m_bIsGameRunning = true;
while( msg.message != WM_QUIT && m_bIsGameRunning )
{
    if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
        g_pWindow->HandleMessage(msg); // translate and dispatch the message
    else
    {
        // *Update*
        loops = 0;
        while( GetTickCount() > next_game_tick && loops < MAX_FRAMESKIP)
        {
            Update();

            next_game_tick += SKIP_TICKS;
            loops++;
        }

        // *Draw*
        Render();
    }
}
m_bIsGameRunning = false;
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.