На главную SpbMap

Разработка игр для Series 60 платформы. Часть 3 - Таймер



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

Разрешающая способность таймеров в Symbian OS не велика, но ее вполне достаточно для типичных целей - таймеры ядра обеспечивают точность 1/64 секунды на устройстве и 1/10 на эмуляторе (Чтобы узнать фактическое значение, используйте UserHal::TickPeriod). Данный интервал округляется вверх до самого близкого значения разрешающей способности частоты сигнала системного времени.

Ниже приведены виды таймеров, применяемых в Symbian OS:

  • Простой таймер, реализуемый RTimer, обеспечивает генерацию событий после заданного промежутка времени или в определенное время. RTimer обеспечивает самый низкий уровень доступа к системному таймеру. Этот таймер можно использовать, когда движок игры пишется с использованием Active Objects.

  • Периодический таймер (CPeriodic) генерирует события периодически через определенный промежуток времени. Сообщение передается приложению через обратный вызов (TCallBack), который задается при создании таймера. Именно этот таймер наиболее широко используется в играх. Он очень прост, и, как правило, для игры хватает одного таймера.

  • Таймер биения (CHeartBeat) подобен периодическому, но имеет некоторые дополнительные возможности. Он использует обратный вызов для информирования о пропуске события таймера (то есть о том, что таймер не обработан во время). CPeriodic неточен. Он задерживает события пока приложение не будет готово его обработать.

Дополнительные возможности таймера биения (информирование о пропущенных событиях MBeating::Synchronize) редко используются, поскольку игры, как правило, не требуют очень точной синхронизации. Обычно нужно знать только время, прошедшее с предыдущего вызова. Точное время необходимо, например, чтобы рассчитать новое положение спрайта, основываясь на его предыдущем положении и скорости движения. Небольшая погрешность таймера не оказывает существенного влияния на результат.

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

// запуск таймера
void CMyGameView::StartTimerL()
{
     // интервал в миллисекундах; 100000 соответствует 1/10 секунды
     const TInt KTickInterval = 100000;
     iPeriodic = CPeriodic::NewL(CActive::EPriorityLow );
     iPeriodic->Start(KTickInterval, KTickInterval,TCallBack(Tick, this));
}

// Останавливаем таймер
void CMyGameView::StopTimer()
{
     iPeriodic->Cancel();
     delete iPeriodic;
     iPeriodic = NULL;
}

// Вызывается таймером по прошествии заданного интервала.
// Этот метод должен быть статическим
TInt CMyGameView::Tick(TAny* aObject)
{
     // вызываем не статический метод
     ((CMyGameEngine*)aObject)->NextTick();
     // позволяем таймеру продолжить его работу
     return 1;
}
// нестатическое событие таймера, вызываемое статическим Tick()
void CMyGameView::NextTick()
{
     TTime currentTime;
     currentTime.HomeTime();
     TInt64 currentTick = currentTime.Int64();
     // Вычисляем время, прошедшее с послдеднего вызова в миллисекундах
     // iLastTick текущее время с момента предыдущего срабатываения таймера
     TInt64 frameTime = currentTick - iLastTick;
     iLastTick = currentTick;
     // Обновляем экран согласно frameTime
     switch(iGameState)
          {
          case EPlayingTheGame:
               // Вычисляем положение спрайта и перерисовываем экран
               HandleGameTick(frameTime);
               break;
          case EWatchingTheIntro:
               // Заставка к игре может обрабатываться этим же таймером
               HandleIntroTick(frameTime);
               break;
          // Здесь же могут обрабатываться любые другие состояния игры
          }
 }

Использования нескольких таймеров обычно не требуется. Это делает структуру игры не такой наглядной, и может вызвать разные неприятные эффекты, особенно если несколько таймеров используются в одном игровом состоянии. Поскольку таймеры используют Active Object, на Active Scheduler ложиться дополнительная нагрузка, кроме того расходуются системные ресурсы.

Приоритет таймера и загруженность Active Scheduler сказывается на точности таймера. Вы не должны перегружать задачами планировщика. События таймера должны обрабатываться как можно быстрее. Таймер должен иметь низкий приоритет, а интервал таймера должен быть по возможности велик. Эти предосторожности позволят избежать ошибок, когда планировщик не справляется с входящими событиями и приложение начинает тормозить.


Перевод: aRix.



На главную SpbMap
Hosted by uCoz