aCTimer Timer;
void Loop()
{
Timer.Attach();
}
Attach: Синхронизирует объект класса с циклом.
подробно
Отвечает за привязку объекта к циклу, обеспечивая корректную обработку возвращаемых значений физических таймеров.
Tick: выполняет большинство операций над таймерами.
подробно
Экземпляр класса содержит безмерное хранилище таймеров (структура CTimer), обращение к которым происходит посредством метода Tick ( или оператор () ), принимающим 3 значения:
ид таймера,
задержка (в мс. дэфолт 100мс),
режим:
T_LINEAR – Возвращает значение каждую итерацию с учётом производительности игры.
T_PRIMARY – Работает аналогично первому, но возвращает значение уже на этапе регистрации.
T_EXACT – Возвращает значение каждую итерацию без учёта погрешности на производительность игры. Обращаясь к таймеру (а это происходит через его id) которого не существует, он автоматически создастся (назовем это моментом регистрации).
Пример ниже демонстрирует обращение к таймерам. Можно заметить, что объектной целью в обоих случаях является экземпляр имеющий id 10. По этому выполнения обоих условий будет всегда идентично.
В примере ниже представлен таймер, задержка которого будет постепенно расти:
Код ниже сработает спустя 5 секунд с момента объявления объекта, после чего его выполнение прервется:
В примере ниже описаны 3 эквивалентных вызова линейного таймера:
В примере ниже таймер вернет значение только 1 раз при объявлении, после чего сразу заморозится:
*Глобально принципиальной разницы о том, какой же таймер использовать - нету. Все происходит на усмотрение программиста - исключительно на его понимание работы режимов и ситуации, для которой он выбирается.*
ид таймера,
задержка (в мс. дэфолт 100мс),
режим:
T_LINEAR – Возвращает значение каждую итерацию с учётом производительности игры.
T_PRIMARY – Работает аналогично первому, но возвращает значение уже на этапе регистрации.
T_EXACT – Возвращает значение каждую итерацию без учёта погрешности на производительность игры. Обращаясь к таймеру (а это происходит через его id) которого не существует, он автоматически создастся (назовем это моментом регистрации).
Пример ниже демонстрирует обращение к таймерам. Можно заметить, что объектной целью в обоих случаях является экземпляр имеющий id 10. По этому выполнения обоих условий будет всегда идентично.
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10))
<...>
while(...)
{
if(Timer.Tick(10))
<...>
}
}
Задержка определяет интервал срабатывания таймера. Задержку можно изменить во время обращения к таймеру. Изменения войдут в силу с новой итерацией. В примере ниже представлен таймер, задержка которого будет постепенно расти:
aCTimer Timer;
int c=0;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,c++))
<...>
}
Если установить задержку таймера на -1, то он заморозится. Код ниже сработает спустя 5 секунд с момента объявления объекта, после чего его выполнение прервется:
aCTimer Timer;
int c = 5000;
void Loop()
{
if(Timer.Tick(10,с))
c = -1;
}
При объявлении таймера задержку достаточно указать один раз.aCTimer Timer;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,2000)) //Работает раз в 2 секунды
<...>
if(Timer.Tick(10)) //Таймер работает одновременно с предыдущим
<...>
}
T_LINEAR: Режим установлен по умолчанию. Вступает в работу не сразу, а через итерацию, равной задержке.В примере ниже описаны 3 эквивалентных вызова линейного таймера:
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,200))
<...>
if(Timer.Tick(10,200,0))
<...>
if(Timer.Tick(10,200,T_LINEAR))
<...>
}
T_PRIMARY: Режим позволяет сработать таймеру в момент его создания. Таким образом, можно создавать конструкции, которые вызываются лишь 1 раз за время своего существования. В примере ниже таймер вернет значение только 1 раз при объявлении, после чего сразу заморозится:
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,-1,T_PRIMARY))
<...>
}
T_ EXACT: Строгий таймер является аналогом T_LINEAR. Разница заключается в том, что линейный таймер сглаживает погрешности производительности игры и подстраивается под нее, строгие же наоборот избегает какого-либо контакта с движком, выполняясь независимо от него. Полезно выбирать строгий режим при необходимости использования коротких задержек при низкой частоте цикла с целью решения математически точных функций или создания конструкций восстановления *потерянных итераций*. Потерянные итерации - это своевременно невыполненные функции движка, обусловленные сбоем, зависанием, более медленным циклом по отношению к таймеру или из-за других подобных проблем. о восстановлении см. макрос force. *Глобально принципиальной разницы о том, какой же таймер использовать - нету. Все происходит на усмотрение программиста - исключительно на его понимание работы режимов и ситуации, для которой он выбирается.*
New: создаёт дочерний экземпляр относительно таймера.
подробно
Так как таймеры циклозависимы, использовать один таймер в другом, пользуясь при этом одним и тем же экземпляром, - нельзя, поскольку каждый физический объект является циклом с собственной задержкой. Метод New автоматически создаёт экземпляр aCTimer относительно заданного объекта CTimer. (aCTimer::CTimer[]->aCTimer)
Ниже приводится пример регистрации новго экземпляра aCTimer внутри объекта CTimer с id 10:
Ниже приводится пример регистрации новго экземпляра aCTimer внутри объекта CTimer с id 10:
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,200,1))
{
if(Timer.New(10)->Tick(10,400))
<...>
}
}
Delete: ручное удаление таймера.
подробно
Удаление, в основном, происходит автоматически внутри экземпляра aCTimer. Для общего понимания: следить за поведением таймеров нам помогает метод Attach. Если появляется объект, который по каким-либо причинам перестает использоваться, - он сразу удаляется. Происходит это не моментально, а только после того, как алгоритм в этом точно убедится (Связь разрывается, если не происходит обращений через метод Tick).
Так вот бывают случаи, когда встает задача избавиться от таймера без перекрытия метода Tick. В этом поможет Delete для моментального уничтожения объекта.
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(KeyPress(KEY_0))
{
if(Timer.Tick(10,500,T_PRIMARY))
<...>
}
else
Timer.Delete(10);
}
Exist: проверяет существование таймера.
подробно
Данный метод возвращает результат существования таймера. С его помощью можно отслеживать момент удаления таймеров, регистрировать новые, уникальные и многое другое.
В примере ниже представлен вариант, где по некоторому условию необходимо удалить таймер 10, если он существует:
В примере ниже представлен вариант, где по некоторому условию необходимо удалить таймер 10, если он существует:
aCTimer Timer;
void Loop()
{
Timer.Attach();
if(...)
if(Timer.Exist(10))
Timer.Delete(10);
}
force: макрос программного восстановления итераций.
подробно
force – это цикл, отслеживающий число пропущенных по каким-либо причинам итераций.
Представим ситуацию: имеется таймер частотой 100мс. Вдруг выполнение программы по неизвестным причинам приостанавливается на 2 секунды. В момент отвисания приложения теряется 20 итераций (2000 / 100). force отследит этот разрыв и автоматически восстановит его.
В примере ниже представлен таймер 10 и вписанный в него дочерний объект. Счётчики i и j считают количество итераций таймеров.
В следующем примере результат счётчика j будет больше счётчика i в 5 раз.
Представим ситуацию: имеется таймер частотой 100мс. Вдруг выполнение программы по неизвестным причинам приостанавливается на 2 секунды. В момент отвисания приложения теряется 20 итераций (2000 / 100). force отследит этот разрыв и автоматически восстановит его.
В примере ниже представлен таймер 10 и вписанный в него дочерний объект. Счётчики i и j считают количество итераций таймеров.
aCTimer Timer;
int i = 0;
int j = 0;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,1000))
{
i++;
if(Timer.New(10)->Tick(20,200,T_PRIMARY))
{
j++;
}
}
}
На выходе можно заметить, что значения i и j равны, даже при разных задержках. Это обусловлено тем, что вложенный таймер не может выполняться раньше родительского. Чтобы исправить это, используем макрос force. Для исключения погрешностей воспользуемся режимом T_EXACT. В следующем примере результат счётчика j будет больше счётчика i в 5 раз.
aCTimer Timer;
int i = 0;
int j = 0;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,1000))
{
i++;
force(Timer.New(10)->Tick(20,200,T_EXACT))
{
j++;
}
}
}
Макрос force также может принимать условия, в которых, например, можно заблокировать выполнение дочернего таймера, если значение счётчика i чётное. Соответственно результат счётчика j на выходе будет в 2 раз меньше предыдущего примера.
aCTimer Timer;
int i = 0;
int j = 0;
void Loop()
{
Timer.Attach();
if(Timer.Tick(10,1000))
{
i++;
force(Timer.New(10)->Tick(20,200,T_EXACT) && i%2 != 0)
{
j++;
}
}
}