Thinking (Обновление)
Think
(обновление) позволяет Entity (энтити) объекту планировать запуск кода в определенное время. Think
может работать постоянно, что позволяет создавать автономные энтити объекты.
Планирование
Функция SetNextThink()
настраивает следующий момент обновления энтити. Принимает значения float (число с плавающей запятой) .
void CMyEntity::Spawn()
{
BaseClass::Spawn();
SetNextThink( gpGlobals->curtime ); // Запустить Think прямо сейчас (обновить)
}
void CMyEntity::Think()
{
BaseClass::Think(); // Всегда пишите это здесь, если хотите предопределить функцию Think()
Msg( "Я думаю, следовательно, я существую.\n" );
SetNextThink( gpGlobals->curtime + 1 ); // Обновить еще раз, через 1 секунду
}
Данный код, после создания энтити, каждую секунду выводит сообщение.
Не забывайте использовать gpGlobals->curtime, чтобы задать следующее время обновления относительно текущего времени, после которого была запущена функция Think, иначе может начаться бесконечный цикл.
SetNextThink(0)
или SetNextThink(null)
остановит любые следующие обновления.Создание собственных Think функций
Энтити может иметь любое количество дополнительных Think
функций. Чтобы создать (зарегистрировать) еще одну функцию:
- Создайте свою функцию типа
void
. - Добавьте ее в энтити DATADESC с помощью DEFINE_THINKFUNC().
- Вызовите
SetThink()
и укажите ссылку на вашу функциюThink
(пример внизу). - Проверьте наличие
DECLARE_DATADESC();
в вашем классе.
BEGIN_DATADESC( CMyEntity )
DEFINE_THINKFUNC( MyThink ), // Регистрация новой Think функции
END_DATADESC()
void CMyEntity::Spawn()
{
BaseClass::Spawn();
SetThink( &CMyEntity::MyThink ); // Задать Think указатель на функцию MyThink()
SetNextThink(gpGlobals->curtime);
}
void CMyEntity::MyThink()
{
Msg( "Я думаю, следовательно, я существую.\n" );
SetNextThink( gpGlobals->curtime + 1 );
}
Разделив ваш код на определенные Think
функции можно легко переключаться между режимами работы вашей энтити.
SetThink()
может быть использована и через саму функцию Think
. Следующий вызов обновления будет сделан через новую выбранную функцию.Использование контекстов
Можно запланировать (запустить) одновременно несколько Think
функций с помощью «think contexts» (контексты). Чтобы создать новый контекст:
- Вызовите
RegisterThinkContext(string ContextName)
указав контекст (название) кThink
функции. - Вызовите
SetContextThink(void * Function, float NextThinkTime, string ContextName) укажите функцию которая будет вызвана контекстом и название вашего контекста
- Для последующих вызовов
Think
, используйтеSetNextThink(float NextThinkTime, string ContextName)
BEGIN_DATADESC( CMyEntity )
DEFINE_THINKFUNC( ContextThink ),
END_DATADESC()
void CMyEntity::Spawn()
{
SetNextThink( gpGlobals->curtime ); // Запуск обычного Think - контекста нет
RegisterThinkContext( "TestContext" );
SetContextThink( &CMyEntity::ContextThink, gpGlobals->curtime, "TestContext" );
}
void CMyEntity::Think()
{
BaseClass::Think();
Msg( "Обновление\n" );
SetNextThink( gpGlobals->curtime + .1 );
}
void CMyEntity::ContextThink()
{
Msg( "Контекстное обновление\n" );
SetNextThink(gpGlobals->curtime + .2, "TestContext" );
}
Это создаст два Think
цикла, оба будут выводить определенные сообщения.
Think
функции затронуты не будут.Время
Вот некоторые функции определения времени обновления:
float GetLastThink() // время последнего обновления
float GetNextThink() // время следующего обновления
int GetLastThinkTick() // время прошлого обновления в тиках (10,000,000 тик/ 1 секунд)
int GetNextThinkTick() // время будущего обновления в тиках
Функции GetLast
полезны для управления скорости, с которой что-то происходит.
Это Think
код энтити npc_barnacle фиксирующий скорость движения языка, при смене частоты обновления:
float dt = gpGlobals->curtime - GetLastThink(); // dt - это "delta time (изменение времени относительно прошлого обновления)"
SetAltitude( m_flAltitude + m_flBarnaclePullSpeed * dt ); // смена высоты языка барнакла
Данный код выполняется когда игрока хватает барнакл. Код делает анимацию языка плавной в отличии от скелетной анимации.
ClientThink() - Обновление клиента
Обновления могут быть объявлены и со стороны клиента («Client-Side»), однако есть ограничения. Для одной энтити доступна лишь одна Think
функция.
void C_MyEntity::ClientThink()
{
Msg( "Не нагружайте эту функцию слишком сильно!\n" );
SetNextClientThink( CLIENT_THINK_ALWAYS ); // Обновлять каждый кадр
}
Некоторый примеры client-side обновления:
- Визуальные эффекты / партиклы
- VGUI экран взаимодействия
- Изменение скорости игрока (выполняется на стороне клиента, а также серверов, для избежания прогнозируемых ошибок)
- Ноги страйдеров, привязки веревки (изначально отключено)
Функция SetNextClientThink()
для запуска ClientThink()
. Принимает два значения:
- CLIENT_THINK_ALWAYS
- Выполнять
Think
функцию после каждого кадра клиента. Используйте с осторожностью!Совет:ИспользуйтеgpGlobals->frametime
для регулирования скорости. - CLIENT_THINK_NEVER
- Остановка всех
Think
обновлений клиента.