Ru/Understanding VGUI2 Animation: Difference between revisions
SlasteliNVL (talk | contribs) No edit summary |
SlasteliNVL (talk | contribs) No edit summary |
||
| Line 48: | Line 48: | ||
****Любые значения типов KeyValues ::TYPE_FLOAT и KeyValues ::TYPE_COLOR, которые доступны при вызове '''RequestInfo''' на панели, также можно изменять. <Sup id = "fnote1"> '''[[#Footnotes|1]]'''</sup> | ****Любые значения типов KeyValues ::TYPE_FLOAT и KeyValues ::TYPE_COLOR, которые доступны при вызове '''RequestInfo''' на панели, также можно изменять. <Sup id = "fnote1"> '''[[#Footnotes|1]]'''</sup> | ||
**** [[#Defining animation variables in code|Variables defined in code]] | **** [[#Defining animation variables in code|Variables defined in code]] | ||
*** | *** Допустимые целевые значения: любое значение с плавающей запятой. '''Возможно до четырех значений.''' Поместите несколько значений в кавычки (например, "255 0 0 255" или "512 512") | ||
*** | *** Действующие интерполяторы: | ||
**** | **** Линейный | ||
**** Accel - | **** Accel - начинает двигаться медленно, быстро заканчивается | ||
**** Deaccel - | **** Deaccel - начинает двигаться быстро, заканчивается медленно | ||
**** Spline - | **** Spline - очень плавная интерполяция | ||
**** Pulse - | **** Pulse - использует синусоидальный импульс для интерполяции. Ожидает значение частоты. | ||
**** Flicker - | **** Flicker - использует [http://en.wikipedia.org/wiki/Pseudorandom_number_generator PRNG], чтобы определить, следует ли использовать исходное значение или конечное значение, что вызывает эффект мерцания. Ожидает значение количества шума. {{Tip:ru| И Pulse, и Flicker имеют дополнительное значение, поэтому обязательно укажите его в скриптах.}} | ||
*** | *** Допустимое время начала: любое значение с плавающей запятой. Фактически фактор задержки. | ||
*** | *** Допустимая продолжительность: любое значение с плавающей запятой. | ||
* '''RunEvent''': | * '''RunEvent''': запускает другое событие, запущенное в указанное время. | ||
** | ** Значения: <event name> <start time> | ||
*** | *** Допустимые имена событий: любое событие, определенное в файлах анимации. | ||
* '''StopEvent''': | * '''StopEvent''': останавливает другое событие, которое в данный момент выполняется в указанное время. | ||
** | ** Значения: <event name> <start time> | ||
* '''StopAnimation''': | * '''StopAnimation''': останавливает все анимации, ссылающиеся на указанную переменную на указанной панели. | ||
** | ** Значения: <panel name> <variable> <start time> | ||
* '''StopPanelAnimations''': | * '''StopPanelAnimations''': останавливает все активные анимации, работающие на указанной панели. | ||
** | ** Значения: <panel name> <start time> | ||
* '''SetFont''': {{Todo| | * '''SetFont''': {{Todo:ru|Посмотрим, что это делает.}} | ||
** | ** Значения: <panel name> <<nowiki>font parameter</nowiki>> <<nowiki>font name from scheme</nowiki>> <set time> | ||
* '''SetTexture''': {{Todo| | * '''SetTexture''': {{Todo:ru|Посмотрим, что это делает.}} | ||
** | ** Значения: <panel name> <texture ID> <material name> <set time> | ||
* '''SetString''': {{Todo| | * '''SetString''': {{Todo:ru|Посмотрим, что это делает.}} | ||
** | ** Значения: <panel name> <string variable name> <value to set> <set time> | ||
= | = Выполнение анимации = | ||
== | == Доступ к контроллеру == | ||
Во-первых, вам понадобятся некоторые включения. Если вы работаете в классе, который использует пространство имен vgui, вы можете вызвать контроллер анимации, включив '''vgui_controls / AnimationController.h''' и назвав его так: | |||
<source lang="cpp"> | <source lang = "cpp"> | ||
vgui::GetAnimationController() | vgui ::GetAnimationController () | ||
</source> | </source> | ||
Если вы не используете пространство имен vgui, вам необходимо включить как '''clientmode.h''', так и '''vgui_controls/AnimationController.h''', и вызвать контроллер анимации следующим образом: | |||
<source lang="cpp"> | <source lang = "cpp"> | ||
g_pClientMode->GetViewportAnimationController() | g_pClientMode-> GetViewportAnimationController () | ||
</source> | </source> | ||
== | == Выполнение событий == | ||
Событие может быть выполнено с помощью метода StartAnimationSequence, который имеет две перегрузки. Один просто берет имя события и ищет панели отдельно, начиная с корневой панели, а другой берет имя события и указатель на панель, в которой находятся элементы управления, которые будут анимированы. | |||
<source lang="cpp"> | <source lang="cpp"> | ||
| Line 101: | Line 101: | ||
</source> | </source> | ||
=== | === Определение переменных анимации в коде === | ||
Определить переменную, которая может использоваться в файлах событий, несложно, и для этого используется следующий макрос: | |||
<source lang="cpp"> | <source lang="cpp"> | ||
#define CPanelAnimationVar( type, name, scriptname, defaultvalue )\ | #define CPanelAnimationVar( type, name, scriptname, defaultvalue )\ | ||
| Line 108: | Line 108: | ||
</source> | </source> | ||
Просматривая ссылки на код, кажется, что это нормально работает для: <sup id="fnote2">'''[[#Footnotes|2]]'''</sup> | |||
* '''Colors:''' CPanelAnimationVar( Color, m_cChangableColor, "Changable_Color", "0 0 0 0" ); | * '''Colors:''' CPanelAnimationVar( Color, m_cChangableColor, "Changable_Color", "0 0 0 0" ); | ||
* '''Fonts:''' CPanelAnimationVar( vgui::HFont, m_hChangableFont, "FontOverride", "DefaultSmall" ); | * '''Fonts:''' CPanelAnimationVar( vgui::HFont, m_hChangableFont, "FontOverride", "DefaultSmall" ); | ||
| Line 115: | Line 115: | ||
* '''Booleans:''' CPanelAnimationVar( bool, m_bChangableBool, "BoolOverride", "0" ); | * '''Booleans:''' CPanelAnimationVar( bool, m_bChangableBool, "BoolOverride", "0" ); | ||
== | == Выполнение динамической анимации == | ||
События удобны для статической анимации, но если вы хотите загружать любой аргумент на лету, вам понадобится динамическая анимация. Это на удивление просто! | |||
=== | === Подготовка к запуску анимации === | ||
Интересующий нас метод называется RunAnimationCommand и принимает аргументы аналогично событиям, определенным выше. | |||
{{Note| | {{Note:ru|Если вы обращаетесь к контроллеру через g_pClientMode, вам нужно вызвать метод '''UpdateAnimations''' вручную в методе '''OnThink()''' вашей панели.}} | ||
'''RunAnimationCommand''' имеет две перегрузки: одну для одного значения, а другую для нескольких значений. К сожалению, многозначный использует класс Color для загрузки любых значений, что означает, что значения будут усечены до целых чисел и очень быстро обернутся! Чтобы смягчить это, давайте создадим новую перегрузку: | |||
Скопируйте это в другие перегрузки '''RunAnimationCommand''' в '''AnimationController.cpp''': | |||
<source lang="cpp"> | <source lang="cpp"> | ||
| Line 165: | Line 165: | ||
void RunAnimationCommand(vgui::Panel *panel, const char *variable, PublicValue_t targetValue, float startDelaySeconds, float durationSeconds, Interpolators_e interpolator, float animParameter = 0 ); | void RunAnimationCommand(vgui::Panel *panel, const char *variable, PublicValue_t targetValue, float startDelaySeconds, float durationSeconds, Interpolators_e interpolator, float animParameter = 0 ); | ||
</source> | </source> | ||
{{Note| | {{Note:ru|Я знаю, что есть прекрасная структура Value_t, которую мы также можем использовать, но когда я сделал ее общедоступной, весь класс пошел наперекосяк. Не стесняйтесь искать правильную реализацию.}} | ||
=== | === Анимация бега === | ||
Теперь мы в деле! Вы можете легко вызывать анимацию через контроллер. Вот пример того, как программно изменить размер ImagePanel: | |||
Допустим, у нас есть ImagePanel с именем '''"overviewImage"''', который определен в .res файле нашей панели. Сначала получаем панель: | |||
<source lang="cpp"> | <source lang="cpp"> | ||
m_pOverviewImage = dynamic_cast<ImagePanel*>( FindChildByName( "overviewImage ", false ) ); | m_pOverviewImage = dynamic_cast<ImagePanel*>( FindChildByName( "overviewImage ", false ) ); | ||
</source> | </source> | ||
{{Note| | {{Note:ru|Поместите это в конструктор класса сразу после загрузки файла ресурсов. Если вы запутались, прочтите это:[[Understanding_VGUI2_Resource_Files#Loading_a_resource_file|Loading a Resource File]].}} | ||
Затем вы можете изменить размер ImagePanel следующим образом: | |||
<source lang="cpp"> | <source lang="cpp"> | ||
AnimationController::PublicValue_t newSize; | AnimationController::PublicValue_t newSize; | ||
| Line 189: | Line 189: | ||
= | = Сноски = | ||
1. | 1. «AnimationController ::GetValue (ActiveAnimation_t & anim, Panel * panel, UtlSymId_t var)» содержит соответствующий код. | ||
2. | 2. Вы также могли заметить, что '''CPanelAnimationVarAliasType''' также является определением и принимает дополнительный параметр: тип алиаса. | ||
<source lang="cpp"> | <source lang="cpp"> | ||
// Only the first line | // Only the first line | ||
| Line 198: | Line 198: | ||
</source> | </source> | ||
Этот псевдоним типа является строкой и используется при преобразовании значений по умолчанию на основе строк в правильные, а также может использоваться для пользовательской обработки. Эта обработка выполняется в '''Panel ::InitPropertyConverters()'''. Это может быть хорошим началом, если вы хотите расширить эту функциональность на другие типы переменных. | |||
[[Category:Programming]] | [[Category:Programming]] | ||
[[Category:VGUI]] | [[Category:VGUI]] | ||
Revision as of 17:42, 19 June 2021
Вступление
VGUI2 имеет довольно мощную систему анимации для анимации как элементов HUD, так и панелей VGUI. Вот относительно полный обзор того, что с ним можно делать.
Обзор архитектуры
Система анимации определена в AnimationController.cpp, который можно найти в vgui2/vgui_controls. Он очень обширный, но основная концепция такова:
- Добавлять анимацию можно несколькими способами
- Запускайте эти анимации каждый тик, используя функцию интерполятора для вычисления промежуточного значения.
Есть два основных способа добавления анимации, которые представляют собой определяемые сценарием события и динамические анимации, которые выполняются во время выполнения.
События
События анимации могут быть загружены из двух источников, оба из которых находятся в папке scripts:
- Манифест сценария анимации: hudanimations_manifest.txt. Если он не найден, загружается последний:
- Один файл сценария: HudAnimations.txt.
Манифест это обычный файл KeyValue. Он будет загружать каждый файл в манифесте:
"HudAnimationManifest"
{
"file" "scripts/HudAnimations.txt"
// You can add more here
}
Макет файла
Открыв HudAnimations.txt, вы увидите множество событий, используемых в Half-Life 2. Вот синтаксис события:
event <EVENTNAME>
{
<COMMAND> <ARGUMENTS>
}
Обзор событий
Вверху файла вы увидите прекрасный обзор возможных команд и их аргументов. Вот обновленный обзор (в коде есть кое-что новое):
- Animate
- Аргументы: <panel name> <variable> <target value(s)> <interpolator> <start time> <duration>
- Допустимые названия панелей: любая панель VGUI или HUD.
- Допустимые значения: Template:Note:ru
- Унарный (1 аргумент): Xpos, Ypos, Ширина, Высота, Блюр, Прозрачность(Альфа), Прозрачность при выборе элемента
- Двоичный (2 аргумента): Позиция, Размер
- Более двух: FgColor, BgColor, TextColor, Ammo2Color Template:Tip:ru
- Неизвестный: 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, чтобы определить, следует ли использовать исходное значение или конечное значение, что вызывает эффект мерцания. Ожидает значение количества шума. Template:Tip:ru
- Допустимое время начала: любое значение с плавающей запятой. Фактически фактор задержки.
- Допустимая продолжительность: любое значение с плавающей запятой.
- Аргументы: <panel name> <variable> <target value(s)> <interpolator> <start time> <duration>
- RunEvent: запускает другое событие, запущенное в указанное время.
- Значения: <event name> <start time>
- Допустимые имена событий: любое событие, определенное в файлах анимации.
- Значения: <event name> <start time>
- StopEvent: останавливает другое событие, которое в данный момент выполняется в указанное время.
- Значения: <event name> <start time>
- StopAnimation: останавливает все анимации, ссылающиеся на указанную переменную на указанной панели.
- Значения: <panel name> <variable> <start time>
- StopPanelAnimations: останавливает все активные анимации, работающие на указанной панели.
- Значения: <panel name> <start time>
- SetFont: Template:Todo:ru
- Значения: <panel name> <font parameter> <font name from scheme> <set time>
- SetTexture: Template:Todo:ru
- Значения: <panel name> <texture ID> <material name> <set time>
- SetString: Template:Todo:ru
- Значения: <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 и принимает аргументы аналогично событиям, определенным выше.
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 );
Анимация бега
Теперь мы в деле! Вы можете легко вызывать анимацию через контроллер. Вот пример того, как программно изменить размер ImagePanel:
Допустим, у нас есть ImagePanel с именем "overviewImage", который определен в .res файле нашей панели. Сначала получаем панель:
m_pOverviewImage = dynamic_cast<ImagePanel*>( FindChildByName( "overviewImage ", false ) );
Затем вы можете изменить размер 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(). Это может быть хорошим началом, если вы хотите расширить эту функциональность на другие типы переменных.