Анимация в VGUI2

From Valve Developer Community
Jump to: navigation, search
English (en)Русский (ru)
... Icon-Important.png

Вступление

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

Обзор архитектуры

Система анимации определена в AnimationController.cpp, который можно найти в vgui2/vgui_controls. Он очень обширный, но основная концепция такова:

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

Есть два основных способа добавления анимации, которые представляют собой определяемые сценарием события и динамические анимации, которые выполняются во время выполнения.

События

События анимации могут быть загружены из двух источников, оба из которых находятся в папке scripts:

  • Манифест сценария анимации: hudanimations_manifest.txt. Если он не найден, загружается последний:
  • Один файл сценария: HudAnimations.txt.
Note.pngNote:Несмотря на то, что прямо в названии написано «Hud», события также могут быть определены для панелей VGUI.


Манифест это обычный файл KeyValue. Он будет загружать каждый файл в манифесте:

"HudAnimationManifest"
{
	"file" "scripts/HudAnimations.txt"
	// You can add more here
}
Tip.pngTip:Скорее всего, в директории scripts не будет ни hudanimations_manifest.txt, ни HudAnimations.txt. Вы можете найти последний в директории hl2/scripts/.

Макет файла

Открыв HudAnimations.txt, вы увидите множество событий, используемых в Half-Life 2. Вот синтаксис события:

event <EVENTNAME>
{
	<COMMAND>	<ARGUMENTS>
}

Обзор событий

Вверху файла вы увидите прекрасный обзор возможных команд и их аргументов. Вот обновленный обзор (в коде есть кое-что новое):

  • Animate
    • Аргументы: <panel name> <variable> <target value(s)> <interpolator> <start time> <duration>
      • Допустимые названия панелей: любая панель VGUI или HUD.
      • Допустимые значения:
        Note.pngNote:Значения курсивом (Italic) работают только для панелей HUD и/или выбора оружия.
        • Унарный (1 аргумент): Xpos, Ypos, Ширина, Высота, Блюр, Прозрачность(Альфа), Прозрачность при выборе элемента
        • Двоичный (2 аргумента): Позиция, Размер
        • Более двух: FgColor, BgColor, TextColor, Ammo2Color
          Tip.pngTip:Цветовые переменные также могут ссылаться на определенный схемой цвет вместо значения RGBA, например FgColor "BrightDamagedFg"
        • Неизвестный: TextScan
        • Любые значения типов KeyValues ​​::TYPE_FLOAT и KeyValues ​​::TYPE_COLOR, которые доступны при вызове RequestInfo на панели, также можно изменять. 1
        • Variables defined in code
      • Допустимые целевые значения: любое значение с плавающей запятой. Возможно до четырех значений. Поместите несколько значений в кавычки (например, "255 0 0 255" или "512 512")
      • Действующие интерполяторы:
        • Линейный
        • Accel - начинает двигаться медленно, быстро заканчивается
        • Deaccel - начинает двигаться быстро, заканчивается медленно
        • Spline - очень плавная интерполяция
        • Pulse - использует синусоидальный импульс для интерполяции. Ожидает значение частоты.
        • Flicker - использует PRNG, чтобы определить, следует ли использовать исходное значение или конечное значение, что вызывает эффект мерцания. Ожидает значение количества шума.
          Tip.pngTip: И Pulse, и Flicker имеют дополнительное значение, поэтому обязательно укажите его в скриптах.
      • Допустимое время начала: любое значение с плавающей запятой. Фактически фактор задержки.
      • Допустимая продолжительность: любое значение с плавающей запятой.
  • RunEvent: запускает другое событие, запущенное в указанное время.
    • Значения: <event name> <start time>
      • Допустимые имена событий: любое событие, определенное в файлах анимации.
  • StopEvent: останавливает другое событие, которое в данный момент выполняется в указанное время.
    • Значения: <event name> <start time>
  • StopAnimation: останавливает все анимации, ссылающиеся на указанную переменную на указанной панели.
    • Значения: <panel name> <variable> <start time>
  • StopPanelAnimations: останавливает все активные анимации, работающие на указанной панели.
    • Значения: <panel name> <start time>
  • SetFont:
    Blank image.pngTodo: Посмотрим, что это делает.
    • Значения: <panel name> <font parameter> <font name from scheme> <set time>
  • SetTexture:
    Blank image.pngTodo: Посмотрим, что это делает.
    • Значения: <panel name> <texture ID> <material name> <set time>
  • SetString:
    Blank image.pngTodo: Посмотрим, что это делает.
    • Значения: <panel name> <string variable name> <value to set> <set time>

Выполнение анимации

Доступ к контроллеру

Во-первых, вам понадобятся некоторые включения. Если вы работаете в классе, который использует пространство имен vgui, вы можете вызвать контроллер анимации, включив vgui_controls / AnimationController.h и назвав его так:

 vgui ::GetAnimationController ()

Если вы не используете пространство имен vgui, вам необходимо включить как clientmode.h, так и vgui_controls/AnimationController.h, и вызвать контроллер анимации следующим образом:

 g_pClientMode-> GetViewportAnimationController ()

Выполнение событий

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

 vgui::GetAnimationController()->StartAnimationSequence( "ShowCommentary" ); // Just the event name
 vgui::GetAnimationController()->StartAnimationSequence( this, "MapZoomToLarge" ); // Event name + parent panel (example from CS:S)

Определение переменных анимации в коде

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

 #define CPanelAnimationVar( type, name, scriptname, defaultvalue )\
 	CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, #type )

Просматривая ссылки на код, кажется, что это нормально работает для: 2

  • Colors: CPanelAnimationVar( Color, m_cChangableColor, "Changable_Color", "0 0 0 0" );
  • Fonts: CPanelAnimationVar( vgui::HFont, m_hChangableFont, "FontOverride", "DefaultSmall" );
  • Floats: CPanelAnimationVar( float, m_fChangableFloat, "FloatAnimation", "0" );
  • Integers: CPanelAnimationVar( int, m_iChangableInt, "IntOverride", "0" );
  • Booleans: CPanelAnimationVar( bool, m_bChangableBool, "BoolOverride", "0" );

Выполнение динамической анимации

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

Подготовка к запуску анимации

Интересующий нас метод называется RunAnimationCommand и принимает аргументы аналогично событиям, определенным выше.

Note.pngNote:Если вы обращаетесь к контроллеру через g_pClientMode, вам нужно вызвать метод UpdateAnimations вручную в методе OnThink() вашей панели.


RunAnimationCommand имеет две перегрузки: одну для одного значения, а другую для нескольких значений. К сожалению, многозначный использует класс Color для загрузки любых значений, что означает, что значения будут усечены до целых чисел и очень быстро обернутся! Чтобы смягчить это, давайте создадим новую перегрузку:

Скопируйте это в другие перегрузки RunAnimationCommand в AnimationController.cpp:

 //-----------------------------------------------------------------------------
 // Purpose: Runs a custom command from code, not from a script file
 //-----------------------------------------------------------------------------
 void AnimationController::RunAnimationCommand(vgui::Panel *panel, const char *variable, PublicValue_t targetValue, float startDelaySeconds, float duration, Interpolators_e interpolator, float animParameter /* = 0 */ )
 {
 	// clear any previous animations of this variable
 	UtlSymId_t var = g_ScriptSymbols.AddString(variable);
 	RemoveQueuedAnimationByType(panel, var, UTL_INVAL_SYMBOL);
 
 	// build a new animation
 	AnimCmdAnimate_t animateCmd;
 	memset(&animateCmd, 0, sizeof(animateCmd));
 	animateCmd.panel = 0;
 	animateCmd.variable = var;
 	animateCmd.target.a = targetValue.a;
 	animateCmd.target.b = targetValue.b;
 	animateCmd.target.c = targetValue.c;
 	animateCmd.target.d = targetValue.d;
 	animateCmd.interpolationFunction = interpolator;
 	animateCmd.interpolationParameter = animParameter;
 	animateCmd.startTime = startDelaySeconds;
 	animateCmd.duration = duration;
 
 	// start immediately
 	StartCmd_Animate(panel, 0, animateCmd);
 }

And copy this above the prototype of RunAnimationCommand in AnimationController.h:

 struct PublicValue_t
 {
 	float a, b, c, d;
 };
 void RunAnimationCommand(vgui::Panel *panel, const char *variable, PublicValue_t targetValue, float startDelaySeconds, float durationSeconds, Interpolators_e interpolator, float animParameter = 0 );
Note.pngNote:Я знаю, что есть прекрасная структура Value_t, которую мы также можем использовать, но когда я сделал ее общедоступной, весь класс пошел наперекосяк. Не стесняйтесь искать правильную реализацию.

Анимация бега

Теперь мы в деле! Вы можете легко вызывать анимацию через контроллер. Вот пример того, как программно изменить размер ImagePanel:

Допустим, у нас есть ImagePanel с именем "overviewImage", который определен в .res файле нашей панели. Сначала получаем панель:

 m_pOverviewImage = dynamic_cast<ImagePanel*>( FindChildByName( "overviewImage ", false ) );
Note.pngNote:Поместите это в конструктор класса сразу после загрузки файла ресурсов. Если вы запутались, прочтите это:Loading a Resource File.

Затем вы можете изменить размер ImagePanel следующим образом:

 AnimationController::PublicValue_t newSize;
 newSize.a = 256;
 newSize.b = 256;
 newSize.c = 0; // Unused
 newSize.d = 0; // Unused

 float totalAnimationTime = 3.0f;
 vgui::GetAnimationController()->RunAnimationCommand( m_pOverviewImage , "size", newSize, 0.0f, totalAnimationTime , vgui::AnimationController::INTERPOLATOR_LINEAR );


Сноски

1. «AnimationController ::GetValue (ActiveAnimation_t & anim, Panel * panel, UtlSymId_t var)» содержит соответствующий код.

2. Вы также могли заметить, что CPanelAnimationVarAliasType также является определением и принимает дополнительный параметр: тип алиаса.

 // Only the first line
 #define CPanelAnimationVarAliasType( type, name, scriptname, defaultvalue, typealias ) \

Этот псевдоним типа является строкой и используется при преобразовании значений по умолчанию на основе строк в правильные, а также может использоваться для пользовательской обработки. Эта обработка выполняется в Panel ::InitPropertyConverters(). Это может быть хорошим началом, если вы хотите расширить эту функциональность на другие типы переменных.