* * * Форумы на Наша-Life THREAD * * * -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- THREAD : Проблемный "правильный" код... HELP!!! Started at 06-10-2014 19:38 by Nergal Visit at https://bbs.hl-inside.ru/showthread.php?threadid=57851 -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 1] Author : Nergal Date : 06-10-2014 19:38 Title : Проблемный "правильный" код... HELP!!! Пришла мне тут намедни в голову идея запилить одну вещь. А именно, тележку, которая возит капсулы со всякими 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() ); [color=red]SetSequence( LookupSequence( "out_hook" ) );[/color] // и, наконец выдвинем крюк для захвата пода } } //----------------------------------------------------------------------------- // Назначение: Убрать крюк //----------------------------------------------------------------------------- void CPropRCart::InputRetHook( inputdata_t &inputData ) { Msg( "InputRetHook \n" ); if ( !m_bSequenceHook ) return; // крюк нельзя убрать, если он не был выдвинутым else { Msg( "PlaybackRate pre %f \n", GetPlaybackRate() ); [color=red]SetSequence( LookupSequence( "return_hook" ) );[/color] // убираем крюк 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 ); } } [/code] Проблемные функции выделены красным цветом. Msg вокруг них показывают, что значения SetPlaybackRate не сбрасывается, т.е. дело не в ней. Люди, помогите побороть проблему со скоростью воспроизведения анимаций, а то я уже себе всю голову апстену сломал. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 2] Author : Barnacle Date : 07-10-2014 08:28 Что бы попробовал лично я: 1) Продублировал бы SetPlaybackRate в InputRetHook на всякий случай. 2) Убрал бы из InputRetHook SetNextThink, чтобы проверить, что Thinking ничего не сбивает. :unknown: -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 3] Author : Nergal Date : 07-10-2014 13:47 1) Это уже делал, пробовал даже значение SetPlaybackRate в 10 раз занижать - безрезультатно. 2) И это делал, думая, что запуск Think преждевременно обнуляет значение SetPlaybackRate - и тоже тщетно. Пожалуй, единственное, что мне ещё сегодня пришло в голову, так это попробовать запускать анимации в другой функции. Возможно, что SetSequence конфликтует каким то образом с Input-функциями. Сейчас попробую... -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 4] Author : Barnacle Date : 07-10-2014 14:12 Можно ещё проверить наличие косяков в qc самой модели. Если нет опечаток "fps 3000", то сто́ит попробовать наоборот занизить до "fps 5", например. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 5] Author : Nergal Date : 07-10-2014 14:48 Сделал. Сейчас инпуты выглядят так + собственно выносная функция HookAnimation: [code] //----------------------------------------------------------------------------- // Назначение: Выдвинуть крюк //----------------------------------------------------------------------------- void CPropRCart::InputOutHook( inputdata_t &inputData ) { Msg( "InputOutHook \n" ); if ( !m_bAllowSeqHook ) return; // анимация не возможна, если объект движется else { // в противном случае: SetNextThink( NULL ); // остановим мозг, чтобы он не сбросил значение PlaybackRate в 0 m_bSequenceHook = HookAnimation( LookupSequence( "out_hook" ) ); } } //----------------------------------------------------------------------------- // Назначение: Убрать крюк //----------------------------------------------------------------------------- void CPropRCart::InputRetHook( inputdata_t &inputData ) { Msg( "InputRetHook \n" ); if ( !m_bSequenceHook ) return; // крюк нельзя убрать, если он не был выдвинутым else { m_bSequenceHook = HookAnimation( LookupSequence( "return_hook" ) ); // SetNextThink( gpGlobals->curtime + 3.0f ); // и снова включаем мозг, чтобы возобновить движение по рельсу } } //----------------------------------------------------------------------------- // Назначение: Запуск анимаций крюка //----------------------------------------------------------------------------- bool CPropRCart::HookAnimation( int m_iSeq ) { if ( m_iSeq == LookupSequence( "out_hook" ) ) { m_bSequenceHook = true; } SetPlaybackRate( 0.5f ); SetSequence( m_iSeq ); if ( m_iSeq == LookupSequence( "return_hook" ) ) { m_bSequenceHook = false; } return m_bSequenceHook; } [/code] Результат тот же... :( Вот, тут видно, как первый раз анимашка срабатывает как надо, а начиная со второго, воспроизводится как будто только первый и последний фреймы: [url]https://drive.google.com/file/d/0B9hGlhzWhxEtZHltRDNwSjUzUlk/view?usp=sharing[/url] [size=1][i]Nergal добавил [date]1412689967[/date]:[/i][/size] Понимаешь, если вставлять эту же модель на карту как prop_dynamic и включать те же анимации через SetAnimation, то обе анимации воспроизводятся безупречно. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 6] Author : Barnacle Date : 07-10-2014 15:50 Есть ещё вариант: написать примитивнейшую энтитю, которая только и может, что переключать анимации (без дополнительных условий), и затем обвесить остальным функционалом, если прокатит. Просто я только сейчас заметил несколько булов, к тому же странные конструкции [b]if(!bool)return;else{}[/b] в которых я запутался. Почему не написать просто [b]if(bool){}[/b] ? -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 7] Author : Nergal Date : 07-10-2014 16:28 Вырезал всё. Упростил до такого: [code] //---------------------------------------------------------- // Назначение: Выдвинуть крюк //---------------------------------------------------------- void CPropRCart::InputOutHook( inputdata_t &inputData ) { SetNextThink( NULL ); HookAnimation( LookupSequence( "out_hook" ) ); } //---------------------------------------------------------- // Назначение: Убрать крюк //---------------------------------------------------------- void CPropRCart::InputRetHook( inputdata_t &inputData ) { SetNextThink( NULL ); HookAnimation( LookupSequence( "return_hook" ) ); } //---------------------------------------------------------- // Назначение: Запуск анимаций крюка //---------------------------------------------------------- void CPropRCart::HookAnimation( int m_iSeq ) { SetPlaybackRate( 0.5f ); SetSequence( m_iSeq ); } [/code] Результат тот же ... {Очень много плохих слов} ... Сейчас снесу всё от спауна и далее. Сделал всё как ты посоветовал - простейшая энтити, поубирал все условия (чёт я и правда переборщил с условными конструкциями) и нифига... {где тут смайлик с пистолетом у виска} Может быть для управляемых кодом анимаций в QC чего то надо дописать?! -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 8] Author : Barnacle Date : 07-10-2014 16:53 Это очень странно. В голову больше ничего не приходит, кроме замены SetSequence(int) на SetSequenceByName(char*) и принудительного сбрасывания анимации через SetCycle(0). [QUOTE][i]Оригинальное сообщение от Nergal [/i] [B]Может быть для управляемых кодом анимаций в QC чего то надо дописать?! [/B][/QUOTE]Для таких простых анимаций достаточно $sequence "имя" "файл" fps 30 snap. Впрочем, все опции описаны [url=https://developer.valvesoftware.com/wiki/$sequence]здесь[/url]. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 9] Author : Nergal Date : 07-10-2014 17:04 И SetCycle(0) и StudioFrameAdvance() (подсмотрел у вальвы) пристраивал. За эти три дня, что я с ней вожусь, разве что заклинания не читал. SetSequenceByName(char*) тоже втыкал, но компилятор ругается на неё undeclared identifier'ом, похоже она работает только для неписей. -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 10] Author : Barnacle Date : 07-10-2014 19:14 Короче, решил я сам поэкспериментировать немного... :D Вот рабочий вариант: [quote]#include "cbase.h" #include "tier0/memdbgon.h" #define ENTITY_MODEL "models/combine_camera/combine_camera.mdl" class CTemp : public CBaseAnimating { DECLARE_CLASS(CTemp, CBaseAnimating); public: DECLARE_DATADESC(); virtual void Precache(void); virtual void Spawn(void); void deploy(inputdata_t &inputdata); void retract(inputdata_t &inputdata); void Think(void); }; LINK_ENTITY_TO_CLASS(temp, CTemp); BEGIN_DATADESC(CTemp) DEFINE_INPUTFUNC(FIELD_VOID, "deploy", deploy), DEFINE_INPUTFUNC(FIELD_VOID, "retract", retract), END_DATADESC() void CTemp::Precache(void) { BaseClass::Precache(); PrecacheModel(ENTITY_MODEL); } void CTemp::Spawn(void) { Precache(); BaseClass::Spawn(); SetModel(ENTITY_MODEL); SetSolid(SOLID_BBOX); } void CTemp::deploy(inputdata_t &inputdata) { SetPlaybackRate(0.5f); ResetSequence(LookupSequence("deploy")); SetThink(&CTemp::Think); SetNextThink(gpGlobals->curtime + 0.1f); } void CTemp::retract(inputdata_t &inputdata) { SetPlaybackRate(0.5f); ResetSequence(LookupSequence("retract")); SetThink(&CTemp::Think); SetNextThink(gpGlobals->curtime + 0.1f); } void CTemp::Think(void) { StudioFrameAdvance(); DispatchAnimEvents(this); SetNextThink(gpGlobals->curtime + 0.1f); }[/quote] [quote]@PointClass base(Targetname) studio("models/combine_camera/combine_camera.mdl") = temp [ input deploy(void) : "Enable \ Включить." input retract(void) : "Disable \ Выключить." ][/quote] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 11] Author : Nergal Date : 08-10-2014 19:33 ВСЁ!!! Добился своего! :D Мой код тоже был бы рабочим, если бы я вчера умел пользоваться функцией ResetClientsideFrame(). Барнакл, спасиб тебе огромное за помощь. Вот "причёсанный" и полностью рабочий вариант: [code] #include "cbase.h" #include "tier0/memdbgon.h" class CPropRCart : public CBaseAnimating { public: DECLARE_CLASS( CPropRCart, CBaseAnimating ); DECLARE_DATADESC(); 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 - выдвинут float m_flVelocity; // скорость перемещения объекта float m_flForwardRate; // текущий кадр анимации движения вперёд float m_flBackwardRate; // текущий кадр анимации движения назад }; #define ENTITY_MODEL "models/prop_combine/combine_runcart_001.mdl" #define MOVE_FRAME_AMOUNT 20 // число кадров в анимации вращения колёс 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_flVelocity, FIELD_FLOAT ), 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 ); m_bSequenceHook = false; UseClientSideAnimation(); SetNextThink( gpGlobals->curtime ); } //----------------------------------------------------------------------------- // Назначение: Определение скорости // Управление частотой вращения колёс при движении //----------------------------------------------------------------------------- void CPropRCart::Think( void ) { BaseClass::Think(); // Вычисление скорости объекта и установка скорости анимации m_flVelocity = GetAbsVelocity().Length(); // скорость объекта m_flVelocity /= 20; // из которой вычисляем частоту вращения колёс SetPlaybackRate( m_flVelocity ); // и устанавливаем её // Проверка условий для запуска соответствующей анимации if ( !HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) && !m_bSequenceHook ) // если флаг реверса не установлен, { SetCycle( MOVE_FRAME_AMOUNT - m_flBackwardRate ); SetSequence( LookupSequence( "move_forward" ) ); // едем (крутим колёса) вперёд m_flForwardRate = GetCycle(); } if ( HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) && !m_bSequenceHook ) // если флаг реверса установлен, { SetCycle( MOVE_FRAME_AMOUNT - m_flForwardRate ); SetSequence( LookupSequence( "move_backward" ) ); // едем (крутим колёса) назад m_flBackwardRate = GetCycle(); } SetNextThink( gpGlobals->curtime + 0.1f ); } //----------------------------------------------------------------------------- // Назначение: Выдвинуть крюк //----------------------------------------------------------------------------- void CPropRCart::InputOutHook( inputdata_t &inputData ) { if ( m_flVelocity == 0 ) // анимация возможна, только если объект неподвижен { SetNextThink( NULL ); // остановим мозг, чтобы он не сбросил значение PlaybackRate в 0 ResetClientsideFrame(); m_bSequenceHook = true; // установим флаг, запрещающий движение с выдвинутым крюком SetPlaybackRate( 0.5f ); // установим оптимальную скорость воспроизведения анимаций SetSequence( LookupSequence( "out_hook" ) ); // и, наконец выдвинем крюк для захвата пода } } //----------------------------------------------------------------------------- // Назначение: Убрать крюк //----------------------------------------------------------------------------- void CPropRCart::InputRetHook( inputdata_t &inputData ) { if ( m_bSequenceHook ) // крюк нельзя убрать, если он не был выдвинутым { ResetClientsideFrame(); SetSequence( LookupSequence( "return_hook" ) ); // убираем крюк m_bSequenceHook = false; // после того как анимация захвата пода была завершена, снимаем с "ручника" :) SetNextThink( gpGlobals->curtime + 3.5f ); // и снова включаем мозг, чтобы возобновить движение по рельсу } } //----------------------------------------------------------------------------- // Назначение: Переключить направление вращения колёс //----------------------------------------------------------------------------- void CPropRCart::InputToggleDirection( inputdata_t &inputData ) { if ( !HasSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ) ) { AddSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ); } else { RemoveSpawnFlags( SF_REVERSE_INITIAL_DIRECTION ); } } [/code] -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- [Post 12] Author : Barnacle Date : 08-10-2014 19:49 ResetClientsideFrame? Окей, буду знать. :) -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- The messages has been download from Форумы на Наша-Life at https://bbs.hl-inside.ru at 18.04.2024 11:41:01