Лучше игровые циклы, чем бесконечный цикл + блок? - PullRequest
6 голосов
/ 25 марта 2009

Каждый учебник и игровая среда (даже довольно новая XNA) начинаются с бесконечного цикла, который имеет эквивалент DoEvents () для предотвращения блокировки ОС.

Исходя из неигровой точки зрения, я чувствую, что этот вид кода пахнет довольно странно.
Нет ли лучшей альтернативы?

- EDIT -
Многие ответы говорят, что каждая программа в основном представляет собой цикл. Правда, но я чувствую, что цикл должен выполняться вашей ОС, а не вами. Только ОС обладает всей информацией, необходимой для оптимального распределения ресурсов. Или я здесь упускаю важный момент?

Ответы [ 9 ]

5 голосов
/ 25 марта 2009

Каждое приложение Windows имеет в своей основе цикл, который выглядит примерно так:

BOOL bRet;

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

Работа приложения, а не операционной системы, заключается в обеспечении отправки сообщений.

Как вы, наверное, знаете, в ранних играх Windows использовался альтернативный метод, где вместо вызова блокирующей функции GetMessage они вызывали бы PeekMessage, а затем вызывали основной цикл обработки игры, если не было сообщения для обработки. , Различные формы задержек использовались, чтобы попытаться получить адекватную частоту кадров без 100% загрузки процессора. Просто не было достаточно хорошего таймера, чтобы обеспечить плавную частоту кадров.

Сегодня, возможно, нет необходимости явно писать цикл, который вызывает DoEvents. теперь возможно , чтобы получить плавную частоту кадров, используя встроенные таймеры пула таймеров (отображаются в .NET с помощью System.Threading.Timer и заключены в System.Timers.Timer).

Насколько я помню, были также проблемы со своевременным получением событий мыши и клавиатуры. Мы использовали прямой доступ с клавиатуры и мыши, а не в зависимости от цикла сообщений, поскольку цикл сообщений часто был слишком медленным и иногда приводил к потере информации.

Я несколько лет не писал игры и не знаю, что такое .NET как игровая платформа. Вполне возможно, что ввод по-прежнему является проблемой - что очередь сообщений просто не достаточно быстра, чтобы дать молниеносный ответ, которого хотят разработчики игр. Таким образом, они обходят очередь сообщений для критических задач.

2 голосов
/ 30 марта 2009

Игры (в большинстве случаев) являются симуляторами. Традиционно это означает, что вы обновляете симуляцию, представляете ее текущее состояние (например, визуализируете графику) и повторяете. Естественным представлением для этого является цикл.

С другой стороны, насос сообщений Win32 - это особенность платформы, ориентированная на приложения, управляемые событиями, которые составляют большинство приложений в Windows. Это ни в коем случае не стандарт для приложений на всех платформах, поэтому неудивительно, что не все программное обеспечение хорошо вписывается в модель. Таким образом, чтобы изменить типичную программу для соответствия модели Win32, вы обычно расходуете эту очередь за один раз, один раз за итерацию цикла, используя PeekMessage до тех пор, пока она не станет пустой. Или вы помещаете эту логику в отдельный поток и, при необходимости, используете GetMessage.

Для большинства игр, ориентированных на производительность, другого практического способа сделать это не существует. Во-первых, если вы пытаетесь сделать игру управляемой событиями, а не опрашиваемой, вам потребуется более высокое разрешение по времени, чем может дать вам Windows, если вы хотите сохранить высокую производительность, к которой стремятся многие игры. Во-вторых, Windows - это только одна из платформ, для которых написаны игры, и переработка игры, чтобы она вписалась в модель Win32, будет просто неудобством для специализированных игровых платформ, которые вместо этого ожидают канонический игровой цикл.

Наконец, проблемы с «взятием 100% CPU» неуместны. Большинство современных игр предназначены для использования в полноэкранном режиме с эксклюзивным аппаратным доступом, а не просто как одно из нескольких сосуществующих приложений. Клиенты таких игр на самом деле требуют, чтобы игра максимально использовала их аппаратное обеспечение, и это невозможно сделать, если имеются преднамеренные вызовы Sleep (), или обновления зависят от внешних таймеров, запускающих приложение N раз в секунду. Очевидно, есть исключения для многих игр, например. те, которые предназначены для запуска в основном в окне, но важно отметить различие.

1 голос
/ 25 марта 2009

На Win32 я использую таймер MultiMedia для вызова игрового логика ...

// 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 );

При желании вы можете выполнять все рисование в другом потоке, чтобы логика игры автоматически не зависела от частоты кадров.

1 голос
/ 25 марта 2009

Не понимаю, как это можно сделать по-другому?

Выполнение вашей программы происходит внутри потока (или нескольких потоков, если вам интересно). Наличие gameloop (или win32 GetMessage / DispatchMessage pump) - это все, что нужно для ожидания события, а затем обработать его. Альтернативой будет регистрация обратных вызовов, а затем вызов HandleAllMyMessages (), который внутренне будет делать почти то же самое ... и это на самом деле ничего не купит.

ОС не сможет волшебным образом разделить вашу программу на несколько потоков, поскольку она не знает, что вы хотите делать в этих потоках. Создание нового потока для каждого входящего сообщения будет и адом производительности и синхронизации.

1 голос
/ 25 марта 2009

Лучший цикл - это бесконечный цикл с блокировкой вызова для отправки событий / сообщений. Если ничего не поделаешь, вам действительно стоит не спать, а блокировать в ожидании ОС. Но если ОС действительно не блокируется при опросе на события, спящий режим между опросами - единственное решение, которое предотвращает 100% использование ЦП.

1 голос
/ 25 марта 2009

Все работающие программы никогда не заканчиваются циклами. Хотя в некоторых случаях вы не взаимодействуете с циклом (например, в веб-программировании или других второстепенных программах)

Ваша ОС представляет собой цикл, ожидающий ввода команд. То же самое с игрой. Веб-сервер представляет собой цикл ожидания запросов.

Отличное объяснение от пользователя slim на один из моих собственных вопросов.

0 голосов
/ 06 декабря 2013

MsgWaitForMultipleEvents сочетает в себе функциональность GetMessage / PeekMessage с таймаутом и возможностью ожидания объектов ядра, таких как WaitableTimer.

Я использовал CreateWaitableTimer для установки желаемой частоты кадров вместе с MsgWaitForMultipleEvents для отправки сообщений с большим успехом для очень плавной анимации в прошлом, без ожидания занятости. Хотелось бы, чтобы в других ОС было что-то такое приятное.

0 голосов
/ 25 марта 2009

, если вы не чувствуете себя комфортно по этому поводу, упакуйте его с классом и интерфейсом,

это то, что мы говорим, «принцип открытия и закрытия» открыть интерфейс никогда не менял, закрыть грязную часть.

почему мы используем цикл? потому что это базовая структура нашего компьютера!

0 голосов
/ 25 марта 2009

Очереди сообщений также являются бесконечными циклами, что делает все программы бесконечными циклами.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...