0
\$\begingroup\$

I'm starting to develop some simple 3D game. The basic topic for a start is the game loop.

There is a solution:

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

}

proposed by Syntac_ in this thread.

The above answer revived positive feedback WHILE the solution seems to NOT be valid! When I click on the close ('X') button (or just press ALt+F4) to close the main app window nothing happens - the app is still running! Fast investigation - the problem is that the app receives some extra WM_TIMER message after the WM_QUIT message so the if (msg.message == WM_QUIT) is NEVER reached!

\$\endgroup\$
4
  • \$\begingroup\$ Did you mean to check for the quit message and quit the game inside the peek message loop, instead of outside of it? This problem was already pointed out nine years ago in the thread you linked \$\endgroup\$
    – DMGregory
    Jun 1, 2022 at 20:53
  • \$\begingroup\$ @DMGregory Yes, that'd solve the problem BUT I'm wondering HOW this solution IS approved as valid since as I've told it isn't working!? \$\endgroup\$
    –  darro911
    Jun 1, 2022 at 21:07
  • 2
    \$\begingroup\$ Having the most up votes doesn't mean the solution is valid. Even an accepted answer isn't necessarily proof of correctness or validity. \$\endgroup\$
    – Pikalek
    Jun 1, 2022 at 21:20
  • \$\begingroup\$ It sounds like it works under some conditions which unfortunately are not universal. This is not unusual in software development. Here, folks were probably mainly upvoting the suggestion to use a while loop to check for messages, and the exact handling of quit was considered a minor detail a reader could sort out for themselves. \$\endgroup\$
    – DMGregory
    Jun 1, 2022 at 22:16

2 Answers 2

2
\$\begingroup\$

The general pattern for a Win32 game loop is:

MSG msg = {};
while (WM_QUIT != msg.message)
{
    if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    else
    {
        // Tick which is usually one or more Updates + 1 Render
    }
}

This ensures you will eventually see the WM_QUIT and exit the loop without any message order dependencies. It also makes sure you process all pending application messages before proceeding with the next frame Tick to keep it responsive.

Also make sure in your WndProc you do:

switch(message)
{
case WM_DESTROY:
    PostQuitMessage(0);
    break;
...

and a helper like this is useful too for logic-based triggering of exit:

void ExitGame() noexcept
{
    PostQuitMessage(0);
}

I suspect another problem here is because you are making heavy use of WM_TIMER messages for your game timing, which is really easy to overload the system with requests. It's also 'wall clock' timing which isn't necessarily the right choice for your game timer.

A better answer is do your own time event detection inside the game loop. See this blog post for details on using StepTimer.h.

See GitHub for an bunch of simple game loops plus Direct3D device & swapchain.

\$\endgroup\$
1
\$\begingroup\$

There are other reasons why you might want to quit the game. For example when the player selects "quit to desktop" from the main menu. I would therefore recommend to add a flag variable quitGame and set that variable to true when you want to end the game for any reason. Then just check that variable in your while-loop:

bool quitGame = false;

while (!quitGame) 
{
    while (PeekMessage(&msg,0,0,0,PM_REMOVE)) 
    {
        // Translate and dispatch message
        if (msg.message == WM_QUIT)
        {
            quitGame = true;
        }
    }

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

}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .