Есть ли лучший способ создать этот игровой цикл? (C ++ / Windows)

Я работаю над игрой для Windows, и у меня есть это:

bool game_cont;

LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_QUIT: case WM_CLOSE: case WM_DESTROY: game_cont = false; break;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(/*lots of parameters*/)
{
    //tedious initialization

    //game loop
    while(game_cont)
    {
        //give message to WinProc
        if(!GameRun()) game_cont = false;
    }
    return 0;
}

и мне интересно, есть ли лучший способ сделать это (игнорируя таймеры и т. д. прямо сейчас), чем сделать game_cont глобальным. Короче говоря, мне нужно иметь возможность выйти из while in WinMain из WinProc, чтобы, если пользователь нажимает кнопку закрытия, выходит из игры способом, отличным от того, что игра находится в игровом меню, программа не продолжала работать в памяти. (Как это было, когда я тестировал это без оператора game_cont.. в WinProc.

Да, и кстати, GameRun - это, по сути, логическое значение, которое возвращает false, когда игра заканчивается, и true в противном случае.


person Community    schedule 25.11.2009    source источник
comment
Вы должны выходить только при получении WM_QUIT и обрабатывать WM_DESTROY, вызывая PostQuitMessage.   -  person Ben Voigt    schedule 06.12.2013


Ответы (4)


Да, используйте PeekMessage, это стандарт в разработка игр.

Я считаю, что это лучший подход:

int Run()
{
    MSG msg;
    while(true)
    {
        if(::PeekMessage(&msg,0,0,0 PM_REMOVE))
        {
            if(msg.message == WM_QUIT || 
                       msg.message == WM_CLOSE || 
                       msg.message == WM_DESTROY)
                break;

            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);           
        }
        else
        {
            //Run game code
                    if(!GameRun())
                         break;
        }
    }
} 

Также посмотрите this (особенно первый ответ)

person Daniel Rodriguez    schedule 25.11.2009
comment
Я бы, вероятно, передал значение «окончания игры» в код GameRun, чтобы он мог очиститься, когда вы решите выйти из приложения, а не просто использовать «break». Но общая структура совершенно верна. - person Kylotan; 26.11.2009
comment
Спасибо за комментарий. Да, думаю, так будет лучше. - person Daniel Rodriguez; 28.11.2009
comment
PeekMessage - это правильный подход к выполнению фоновой работы, когда сообщения отсутствуют, но WM_CLOSE и WM_DESTROY не должны обрабатываться в основном цикле сообщений. Прямо сейчас вы собираетесь прервать работу всей программы всякий раз, когда какой-либо дочерний элемент управления или невидимое вспомогательное окно сообщений будет уничтожено! - person Ben Voigt; 06.12.2013

Вы можете использовать exit. Используйте atexit, чтобы убедиться, что WM_CLOSE получает в очередь сообщений, когда пора выходить.

Я не знаю, какой здесь идеальный дизайн, но это идея.

person Steinbitglis    schedule 25.11.2009

Вы можете сделать game_cont static своим основным файлом, который имеет _3 _ / _ 4_, но я не знаю значительно лучшей структуры.

person Justin Love    schedule 25.11.2009

Нет, не делай этого.

WM_QUIT - ваш флаг. GetMessage возвращаемое значение указывает, когда встречается WM_QUIT.

Ваше главное окно никогда не получит WM_QUIT, так как оно не отправляется в окно. WM_CLOSE будет вызывать DestroyWindow по умолчанию, поэтому вам не нужно для этого никакой специальной обработки. Обработайте WM_DESTROY, вызвав PostQuitMessage, что приводит к WM_QUIT в вашем потоке, специальному возвращаемому значению из GetMessage, и останавливает цикл отправки сообщений.

person Ben Voigt    schedule 05.12.2013