2009-03-25 2 views
6

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

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

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

+0

Да, вам не хватает важного отличия в том, что игра не является сервисом ОС. – Hejazzman

ответ

5

приложения для 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); 
    } 
} 

Это работа приложения - не рабочие system - чтобы гарантировать, что сообщения отправляются.

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

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

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

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

+0

Я на самом деле думал, что если бы он сделал таймер, чтобы определить таймер, который знает частоту экрана для создания кадров. Таким образом, на ненужные трассы когда-либо делается. Также идея, придуманная @Bryan Parker, иметь рисунок в отдельном потоке, чтобы вытащить его из остальной части (логика игры/IO) ... –

+0

... как хорошая идея. Я не знаю, насколько это справедливо. –

+1

Большинство игр имеют рендеринг в отдельном потоке. И вы хотите отделить ваши обновления от vsync для тестирования производительности (среди прочих причин). – BigSandwich

1

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

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

Большое объяснение от пользователя slim on one of my own questions.

+0

Вы в основном правы, хотя это верно только для графических программ. для простых приложений и командной строки вы можете легко уйти без основного цикла. –

+0

Добавлено разъяснение. –

+0

Прочтите ваше сообщение, и я действительно это понял. Но поскольку ОС уже делает этот цикл, нехорошо ли зацепиться за этот цикл (использовать события ОС), а затем создать собственный цикл в цикле ОС? –

0

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

-3

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

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

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

+0

Боюсь, что есть недопонимание. Я знаю, как я мог скрыть все уродливые биты, но вопрос в том, почему мы должны реализовывать цикл в цикле ОС. –

1

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

+0

Хорошо, на самом деле я имел в виду сон. (старые DoEvents). Изменит пост, чтобы это отразить. –

1

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

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

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

1

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

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

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

2

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

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

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

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

+0

Фантастический ответ и обзор. –

+0

Принимая 100% -ный процессор, безусловно, является серьезной проблемой и что-то, чего следует избегать. Даже когда вы являетесь полноэкранным передним планом, вы не хотите тратить процессорные циклы. С каждым годом он все больше мешает управлению энергопотреблением. Когда вы написали свой ответ, это было бы всего лишь проблемой для ноутбуков (что по-прежнему достаточно для того, чтобы не сжигать CPU). Сегодня он запустит ядро ​​процессора в Turbo Boost, уменьшив мощность, доступную для встроенного графического процессора. Таким образом, ваша идея забивать все ресурсы для вашей игры фактически снижает ее производительность. -1 –

+0

@BenVoigt - Это действительный момент, но это зависит от того, на какой платформе вы нацеливаетесь. Игры AAA, которые не предназначены исключительно для мобильных или переносных платформ, не будут преднамеренно вводить циклы сна по любой причине и будут масштабировать обработку для заполнения доступных ресурсов ЦП. Более важно то, что от них не ожидается хорошей производительности на интегрированных графических процессорах - они являются гражданами второго сорта в отношении программного обеспечения для игр. Но если вы нацелены на мобильную связь ... это совсем другая история. – Kylotan

0

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

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

Смежные вопросы