Пришла мне тут намедни в голову идея запилить одну вещь. А именно, тележку, которая возит капсулы со всякими NPC-ями по всей цитадели, а то у Вальв её как бы вообще и нет - непонятно каким волшебным образом капсулы скользят по подвесному рельсу.
Для визуального эффекта тележка имеет вращающиеся колёса и поворотный крюк для подвешивания капсул.
Кто то скажет зачем писать для такой фигни код, ведь можно использовать её как prop_dynamic.
Собственно, для чего требовалось писать для неё код:
1) привязать скорость вращения колёс к скорости движения для пущего реализма.
2) упростить управление дополнительными анимациями и связать их логикой с функциями движения.
В результате по пункту 1 всё работает как надо.
Проблема с пунктом 2. А именно, анимации управления крюком воспроизводятся неправильно. Выдвигается крюк с нужной скоростью, как и положено (анимация длится около 3,5 сек), но убирается за долю секунды, хотя её длительность по времени должна быть такой же как и у анимации выдвижения.
Вот код:
code:
#include "cbase.h"
#include "tier0/memdbgon.h"
class CPropRCart : public CBaseAnimating
{
public:
DECLARE_CLASS( CPropRCart, CBaseAnimating );
DECLARE_DATADESC();
CPropRCart()
{
m_bSequenceHook = false;
m_bAllowSeqHook = true;
}
void Spawn( void );
void Precache( void );
void Think( void );
// Входные функции
void InputToggleDirection( inputdata_t &inputData ); // изменение направления вращения колёс
void InputOutHook( inputdata_t &inputData ); // вызов анимации подачи крюка
void InputRetHook( inputdata_t &inputData ); // вызов анимации возврата крюка
private:
bool m_bSequenceHook; // состояние анимации крюка: false - убран, true - выдвинут
bool m_bAllowSeqHook; // false - анимация крюка запрещена, true - анимация крюка разрешена
float m_flVelocity; // скорость перемещения объекта
};
#define ENTITY_MODEL "models/prop_combine/combine_runcart_001.mdl"
LINK_ENTITY_TO_CLASS( vehicle_runcart, CPropRCart );
// Spawnflags
#define SF_REVERSE_INITIAL_DIRECTION 0x00000040 // установка флага реверсирует анимацию вращения колёс
BEGIN_DATADESC( CPropRCart )
DEFINE_FIELD( m_bSequenceHook, FIELD_BOOLEAN ),
DEFINE_FIELD( m_bAllowSeqHook, FIELD_BOOLEAN ),
DEFINE_INPUTFUNC( FIELD_VOID, "ReverseDirection", InputToggleDirection ),
DEFINE_INPUTFUNC( FIELD_VOID, "OutHook", InputOutHook ),
DEFINE_INPUTFUNC( FIELD_VOID, "RetHook", InputRetHook ),
END_DATADESC()
//-----------------------------------------------------------------------------
// Назначение: Прекэширование необходимых объекту ресурсов.
//-----------------------------------------------------------------------------
void CPropRCart::Precache( void )
{
PrecacheModel( ENTITY_MODEL );
BaseClass::Precache();
}
//-----------------------------------------------------------------------------
// Назначение: Настраивает начальное состояние объекта.
//-----------------------------------------------------------------------------
void CPropRCart::Spawn( void )
{
Precache();
SetModel( ENTITY_MODEL );
SetSolid( SOLID_VPHYSICS );
UseClientSideAnimation();
SetNextThink( gpGlobals->curtime );
}
//-----------------------------------------------------------------------------
// Назначение: Определение скорости
// Управление частотой вращения колёс при движении
//-----------------------------------------------------------------------------
void CPropRCart::Think( void )
{
BaseClass::Think();
// Вычисление скорости объекта и установка скорости анимации
m_flVelocity = GetAbsVelocity().Length(); // скорость объекта
m_flVelocity /= 20; // из которой вычисляем частоту вращения колёс
SetPlaybackRate( m_flVelocity ); // и устанавливаем её
// Проверка условий для запуска соответствующей анимации
if ( m_flVelocity == 0 ) // если объект неподвижен, ставим "нейтраль"
{
SetSequence( LookupSequence( "idle" ) );
m_bAllowSeqHook = true; // и даём возможность манипуляций с крюком
Msg( "idle \n" );
}
else
{
if ( !HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) ) // если флаг реверса не установлен,
{
SetSequence( LookupSequence( "move_forward" ) ); // едем (крутим колёса) вперёд
Msg( "move_forward \n" );
}
if ( HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) ) // если флаг реверса установлен,
{
SetSequence( LookupSequence( "move_backward" ) ); // едем (крутим колёса) назад
Msg( "move_backward \n" );
}
m_bAllowSeqHook = false; // запрещаем анимации крюка
}
SetNextThink( gpGlobals->curtime + 0.1f );
}
//-----------------------------------------------------------------------------
// Назначение: Выдвинуть крюк
//-----------------------------------------------------------------------------
void CPropRCart::InputOutHook( inputdata_t &inputData )
{
Msg( "InputOutHook \n" );
if ( !m_bAllowSeqHook ) return; // анимация не возможна, если объект движется
else
{ // в противном случае:
m_bSequenceHook = true; // установим флаг, запрещающий движение с выдвинутым крюком
Msg( "PlaybackRate pre %f \n", GetPlaybackRate() );
SetNextThink( NULL ); // остановим мозг, чтобы он не сбросил значение PlaybackRate в 0
SetPlaybackRate( 0.5f );
Msg( "PlaybackRate aft %f \n", GetPlaybackRate() );
SetSequence( LookupSequence( "out_hook" ) ); // и, наконец выдвинем крюк для захвата пода
}
}
//-----------------------------------------------------------------------------
// Назначение: Убрать крюк
//-----------------------------------------------------------------------------
void CPropRCart::InputRetHook( inputdata_t &inputData )
{
Msg( "InputRetHook \n" );
if ( !m_bSequenceHook ) return; // крюк нельзя убрать, если он не был выдвинутым
else
{
Msg( "PlaybackRate pre %f \n", GetPlaybackRate() );
SetSequence( LookupSequence( "return_hook" ) ); // убираем крюк
Msg( "PlaybackRate aft %f \n", GetPlaybackRate() );
m_bSequenceHook = false; // после того как анимация захвата пода была завершена, снимаем с "ручника"
SetNextThink( gpGlobals->curtime + 4.0f ); // и снова включаем мозг, чтобы возобновить движение по рельсу
}
}
//-----------------------------------------------------------------------------
// Назначение: Переключить направление вращение колёс
//-----------------------------------------------------------------------------
void CPropRCart::InputToggleDirection( inputdata_t &inputData )
{
if ( !HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) )
{
AddSpawnFlags( SF_REVERSE_INITIAL_DIRECTION );
}
else
{
RemoveSpawnFlags( SF_REVERSE_INITIAL_DIRECTION );
}
}
Проблемные функции выделены красным цветом. Msg вокруг них показывают, что значения SetPlaybackRate не сбрасывается, т.е. дело не в ней.
Люди, помогите побороть проблему со скоростью воспроизведения анимаций, а то я уже себе всю голову апстену сломал.