Attention: Here be dragons

This is the latest (unstable) version of this documentation, which may document features not available in or compatible with released stable versions of Godot.

Использование AnimationTree

Введение

Благодаря AnimationPlayer, Godot обладает одной из самых гибких систем анимации, которую вы можете найти в любом игровом движке. Он практически уникален своей способностью анимировать практически любое свойство в любом узле или ресурсе, а также своими выделенными дорожками преобразования, кривыми Безье, вызова функций, аудио и суб-анимации.

Однако поддержка смешивания этих анимаций через AnimationPlayer ограничена, поскольку можно установить только фиксированное время перехода с плавным переходом.

AnimationTree это узел, разработанный для управления сложными переходами.

AnimationTree и AnimationPlayer

Прежде чем начать, учтите, что узел AnimationTree не содержит собственных анимаций. Вместо этого он использует анимации, содержащиеся в узле AnimationPlayer. Вы создаёте, редактируете или импортируете анимации в узле AnimationPlayer, а затем используете AnimationTree для управления воспроизведением.

AnimationPlayer и AnimationTree Можно использовать как в 2D-, так и в 3D-сценах. При импорте 3D-сцен и их анимаций можно использовать name suffixes для упрощения процесса и импорта с правильными свойствами. В конце импортированная сцена Godot будет содержать анимацию в узле AnimationPlayer. Поскольку вы редко используете импортированные сцены напрямую в Godot (они либо создаются как экземпляры, либо наследуются), вы можете поместить узел AnimationTree в новую сцену, содержащую импортированную сцену. После этого укажите узлу AnimationTree на AnimationPlayer, созданный в импортированной сцене.

Вот как это сделано в демо-версии шутера от третьего лица, для справки:

../../_images/animtree_treeandplayersetup.png

Для игрока была создана новая сцена с CharacterBody3D в качестве корня. Внутри этой сцены был создан исходный файл .dae (Collada) и создан узел AnimationTree.

Создание дерева

Чтобы использовать AnimationTree, необходимо задать корневой узел. Корневой узел анимации — это класс, который содержит и оценивает подузлы и выводит анимацию. Существует 3 типа под-узлов:

  1. Узлы анимации, которые ссылаются на анимацию из связанного AnimationPlayer.

  2. Корневые узлы анимации, которые используются для смешивания подузлов и могут быть вложенными.

  3. Узлы смешивания анимации, которые используются в AnimationNodeBlendTree, двумерном графе узлов. Узлы смешивания принимают несколько входных портов и имеют один выходной порт.

Доступно несколько типов корневых узлов:

../../_images/animtree_rootnodes.png
  • AnimationNodeAnimation: Выбирает анимацию из списка и воспроизводит её. Это простейший корневой узел, который обычно не используется в качестве корня.

  • AnimationNodeBlendTree: Содержит несколько дочерних узлов в графе. Доступно множество смешанных узлов, таких как mix, blend2, blend3, one shot и т. д.

  • AnimationNodeBlendSpace1D: Обеспечивает линейное смешивание между двумя узлами анимации. Управляйте положением смешивания в одномерном пространстве (1D) смешивания для смешивания анимаций.

  • AnimationNodeBlendSpace2D: Обеспечивает линейное смешивание между тремя узлами анимации. Управляйте положением смешивания в двумерном пространстве смешивания для смешивания анимаций.

  • AnimationNodeStateMachine: содержит несколько дочерних узлов в графе. Каждый узел используется как состояние, а для переключения между состояниями используются несколько функций.

Дерево смешения

При создании AnimationNodeBlendTree на нижней панели, под вкладкой AnimationTree, появляется пустой 2d график. По умолчанию он содержит только узел Output.

../../_images/animtree_emptyblendtree.webp

Для воспроизведения анимации необходимо подключить узел к выходу. Узлы можно добавить через меню Add Node.. или щёлкнув правой кнопкой мыши по пустому месту:

../../_images/animtree_blendnodes.webp

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

../../_images/animtree_animtooutput.png

Ниже приведено описание других доступных узлов:

Blend2 / Blеnd3

Эти узлы будут смешиваться между двумя или тремя входами по указанному пользователем значению смешения:

../../_images/animtree_blend2.gif

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

../../_images/animtree_filtering.png

Для более сложного смешивания рекомендуется использовать пространства смешивания.

OneShоt

Этот узел выполнит анимацию один раз и вернётся после её завершения. Вы можете настроить время наложения для плавного появления и исчезновения, а также фильтры.

../../_images/animtree_oneshot.gif
# Play child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE)
# Alternative syntax (same result).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_FIRE

# Abort child animation connected to "shot" port.
animation_tree.set("parameters/OneShot/request", AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT)
# Alternative syntax (same result).
animation_tree["parameters/OneShot/request"] = AnimationNodeOneShot.ONE_SHOT_REQUEST_ABORT

# Get current state (read-only).
animation_tree.get("parameters/OneShot/active"))
# Alternative syntax (same result).
animation_tree["parameters/OneShot/active"]

TimeSeek

This node allows you to seek to a time in the animation connected to its in input. Use this node to play an Animation starting from a certain playback position. Note that the seek request value is measured in seconds, so if you would like to play an animation from the beginning, set the value to 0.0, or if you would like to play an animation from 3 seconds in, set the value to 3.0.

../../_images/animtree_timeseek.webp
# Play child animation from the start.
animation_tree.set("parameters/TimeSeek/seek_request", 0.0)
# Alternative syntax (same result).
animation_tree["parameters/TimeSeek/seek_request"] = 0.0

# Play child animation from 12 second timestamp.
animation_tree.set("parameters/TimeSeek/seek_request", 12.0)
# Alternative syntax (same result).
animation_tree["parameters/TimeSeek/seek_request"] = 12.0

TimeScаle

This node allows you to scale the speed of the animation connected to its in input. The speed of the animation will be multiplied by the number in the scale parameter. Setting the scale to 0.0 will pause the animation. Setting the scale to a negative number will play the animation backwards.

../../_images/animtree_timescale.webp

Transition (Переход)

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

../../_images/animtree_transition.webp
# Play child animation connected to "state_2" port.
animation_tree.set("parameters/Transition/transition_request", "state_2")
# Alternative syntax (same result).
animation_tree["parameters/Transition/transition_request"] = "state_2"

# Get current state name (read-only).
animation_tree.get("parameters/Transition/current_state")
# Alternative syntax (same result).
animation_tree["parameters/Transition/current_state"]

# Get current state index (read-only).
animation_tree.get("parameters/Transition/current_index"))
# Alternative syntax (same result).
animation_tree["parameters/Transition/current_index"]

StateMachinе (машина состояний)

При создании AnimationNodeStateMachine на нижней панели, под вкладкой AnimationTree, появляется пустой 2d график. Он по умолчанию содержит состояния Start и End.

../../_images/animtree_emptystatemachine.webp

Чтобы добавить состояния, щёлкните правой кнопкой мыши или используйте кнопку Сreate new nodes, значок которой представляет собой плюс в квадратике. Вы можете добавить анимации, пространства смешивания, деревья смешивания и даже другой StateMachine. Чтобы отредактировать один из этих более сложных подузлов, щёлкните по значку карандаша справа от состояния. Чтобы вернуться к исходному StateMachine, щёлкните по кнопке Root в левом верхнем углу панели.

Прежде чем StateMachine сможет что-либо сделать, состояния должны быть соединены переходами. Чтобы добавить переход, нажмите кнопку connect nodes, которая представляет собой линию со стрелкой вправо, и перетащите её между двумя состояниями. Вы можете создать два перехода между состояниями, по одному в каждом направлении.

../../_images/animtree_connections.gif

Существует 3 типа переходов:

../../_images/animtree_transitiontypes.png
  • Immediate: Немедленно перейдет в следующее состояние.

  • Sync: Немедленно перейдет в следующее состояние, но будет установлено в позицию воспроизведения старого состояния.

  • At End: Дождется окончания воспроизведения текущего состояния, а затем переключится в начало анимации следующего состояния.

У переходов также есть несколько свойств. Щёлкните по переходу, и он отобразится в инспекторе:

../../_images/animtree_statemachinetransitionproperties.webp
  • Xfade Time - время перекрестного затухания между этим состоянием и следующим.

  • Xfade Curve — это плавный переход по кривой, а не линейное смешивание.

  • Reset определяет, воспроизводится ли состояние, в которое вы переключаетесь, с самого начала (true) или нет (false).

  • Приоритет используется совместно с функцией travel() из кода (подробнее об этом позже). При перемещении по дереву предпочтительны переходы с более низким приоритетом.

  • Switch Mode — тип перехода (см. выше). Его можно изменить после создания здесь.

  • Advance Mode определяет режим перехода. Если Disabled, переход не будет использоваться. Если Enabled, переход будет использоваться только во время travel(). Если Auto, переход будет использоваться, если условие перехода и выражение истинны или если условия перехода/выражения отсутствуют.

Advance Condition и Advance Expression

Последние два свойства в переходе StateMachine — это Advance Condition и Advance Expression.. Если для параметра «Advance Mode» установлено значение Авто, они определяют, будет ли переход продвигаться или нет.

Условие «Advance Condition» проверяет true/false. Вы можете указать имя пользовательской переменной в текстовом поле, и когда StateMachine достигнет этого перехода, он проверит, является ли ваша переменная true. Если да, переход продолжается. Обратите внимание, что условие «Advance Condition» проверяет только, что переменная имеет значение true, и не может проверять её на ложность (falseness).

Это сильно ограничивает возможности Advance Condition. Если бы вы хотели осуществить переход туда и обратно на основе одного свойства, вам пришлось бы создать две переменные с противоположными значениями и проверять, является ли хотя бы одна из них истинной. Именно поэтому в Godot 4 было добавлено Advance Expression.

Advance Expression работает аналогично Advance Condition, но вместо проверки истинности одной переменной оно вычисляет любое выражение. Выражение (expression) — это любое выражение, которое можно поместить в оператор if. Вот примеры выражений, которые можно использовать в Advance Expression:

  • is_walking

  • is_walking == true (выполняет действие, аналогичное коду выше)

  • is_walking && !is_idle

  • velocity > 0

  • player.is_on_floor()

Предупреждение

Выражение чувствительно к регистру. Если вы ссылаетесь на свойства движка, такие как velocity в узле CharacterBody3D, вам следует использовать соглашение об именовании snake_case. Если вы ссылаетесь на свойства скрипта, вам следует придерживаться стиля, используемого в самом скрипте, который обычно является snake_case в GDScript и PascalCase в C#.

Вот пример неправильно настроенного перехода StateMachine с использованием Advance Condition:

../../_images/animtree_badanimcondition.webp ../../_images/animtree_badanimcondition.gif

Это не работает, так как в предварительном условии есть переменная !, которую невозможно проверить.

Вот тот же пример, настроенный правильно, с использованием двух противоположных переменных:

../../_images/animtree_goodanimcondition.webp ../../_images/animtree_goodanimcondition.gif

Вот тот же пример, но с использованием расширенного выражения вместо расширенного условия, что устраняет необходимость в двух переменных:

../../_images/animtree_goodanimexpression.webp ../../_images/animtree_goodanimexpression2.webp ../../_images/animtree_goodanimexpression.gif

Для использования расширенных выражений необходимо задать базовый узел расширенных выражений в инспекторе узла AnimationTree. По умолчанию он указывает на сам узел AnimationTree, но должен указывать на любой узел, содержащий скрипт с переменными анимации.

См. также

Advance Expression вычисляется с использованием класса Expression Godot. См. Оценка выражений для получения дополнительной информации о написании выражений.

Путешествие StateMachine

Одна из приятных особенностей реализации StateMachine в Godot — возможность перемещения. Вы можете указать графу перейти из текущего состояния в другое, посетив все промежуточные. Это делается с помощью алгоритма A*. Если нет пути переходов, начинающихся в текущем состоянии и заканчивающихся в конечном, граф телепортируется в конечное состояние.

Чтобы использовать возможность перемещения, необходимо сначала извлечь объект AnimationNodeStateMachinePlayback из узла AnimationTree (он экспортируется как свойство), а затем вызвать одну из его многочисленных функций:

var state_machine = animation_tree["parameters/playback"]
state_machine.travel("SomeState")

Перед началом путешествия необходимо запустить StateMachine. Убедитесь, что вы либо вызвали start(), либо подключили узел к Start.

BlendSpace2D и BlendSpace1D

BlendSpace2D — это узел для расширенного смешивания в двух измерениях. Точки, представляющие анимацию, добавляются в 2D пространство, а затем положение между ними контролируется для определения смешивания:

../../_images/animtree_blendspace2d.gif

You may insert these points anywhere on the graph by right-clicking or using the add point button in the toolbar. On creation, a point gets its name from the chosen animation or AnimationRootNode type. This point can then be renamed by clicking on its name, or repositioned by clicking and dragging the name or the point. If Auto Triangles is enabled, a blend triangle between inserted points will be automatically generated using Delaunay triangulation.

../../_images/animtree_blendspacepoints.webp

This node's animation blend target can be manipulated in the editor by pressing Shift while dragging the left mouse button, or using the dedicated tool.

BlendSpace1D works just like BlendSpace2D, but in a single dimension (a horizontal line). Since triangles are not used, it is able to function with fewer than three blend points.

../../_images/animtree_blendspace1d.webp

Режим синхронизации

Оба класса BlendSpace1D и BlendSpace2D имеют свойство Sync Mode, которое управляет тем, как анимации продвигаются при смешивании. Это заменяет старое логическое свойство sync и обеспечивает более точный контроль.

../../_images/animtree_syncmode_mutable.webp

Доступны четыре режима:

  • None (по умолчанию): Неактивные анимации заморожены и не продвигаются. Только текущая активная (с наибольшим весом) анимация движется вперёд.

  • Independent: Неактивные анимации продвигаются с весом 0. Это соответствует поведению старой настройки sync = true.

  • Cyclic Mutable: Все анимации масштабируются по времени так, чтобы их фазы оставались синхронизированными. Общая длина цикла вычисляется динамически из активных весов смешивания, что означает, что одна несмешанная анимация воспроизводится с нормальной скоростью. Это полезно, когда все ваши анимации имеют один и тот же логический цикл (например, циклы передвижения), но могут немного отличаться по длине.

  • Cyclic Constant: Все анимации масштабируются по времени так, чтобы завершать один полный цикл ровно за Cyclic Length секунд, независимо от их индивидуальной длины. Установите свойство cyclic_length в желаемую длительность цикла (должна быть больше 0).

Предупреждение

Циклические режимы синхронизации требуют, чтобы все точки смешивания использовали AnimationNodeAnimation с конечной, неизменной длиной. Если какая-либо точка смешивания использует другой тип узла, будет показано предупреждение, и циклическая синхронизация не будет применена:

../../_images/animtree_syncmode_warning.webp

Примечание

При использовании любого из циклических режимов с анимациями разной длины применение AnimationNodeTimeSeek к выходу нарушит синхронизацию. В этом случае используйте AnimationNodeAnimation.use_custom_timeline для нормализации длин анимаций перед синхронизацией.

Режим смешивания

By default, blending happens in the Continuous mode, by interpolating points inside the closest triangle in BlendSpace2D, or in the line between points in BlendSpace1D. However, this may not always be the best choice. For instance, when dealing with frame-by-frame 2D animations, you may want to switch to the Discrete mode, in which the intermediate states of the blend do not appear in the result. Alternatively, if you want to retain the current play position when switching between discrete animations, the Carry mode allows you to do so. These modes can be set with the Blend menu.

../../_images/animtree_blendmode.webp

Для лучшего смешивания

Чтобы результаты смешивания были детерминированными (воспроизводимыми и всегда согласованными), смешиваемые значения свойств должны иметь определённое начальное значение. Например, в случае смешивания двух анимаций, если одна анимация имеет дорожку свойств, а другая нет, смешанная анимация вычисляется так, как если бы последняя анимация имела дорожку свойств с начальным значением.

При использовании Дорожки Позиционирования/Вращения/Масштабирования для костей Skeleton3D начальным значением является Bone Rest. Для других свойств начальными значениями являются 0, и если дорожка присутствует в анимации RESET, вместо него используется значение первого ключевого кадра этой дорожки.

Например, в AnimationPlayer, представленном ниже, есть две анимации, но в одной из них отсутствует дорожка свойств для позиционирования.

../../_images/blending1.webp

Это означает, что анимация, в которой отсутствует это, будет обрабатывать эти позиции как Vector2(0, 0).

../../_images/blending2.webp

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

../../_images/blending3.webp ../../_images/blending4.webp

Примечание

Имейте в виду, что анимация RESET предназначена для определения позы по умолчанию при первоначальной загрузке объекта. Предполагается, что она содержит только один кадр и не будет воспроизводиться с использованием временной шкалы.

Также следует помнить, что дорожки Rotation 3D и дорожки свойств для вращения 2D с типом интерполяции, установленным на «Линейный угол» или «Кубический угол», предотвратят повороты более чем на 180 градусов от начального значения в качестве смешанной анимации.

Это может быть полезно для Skeleton3Ds, чтобы предотвратить проникновение костей в тело при смешивании анимаций. Поэтому значения Bone Rest в Skeleton3D должны быть как можно ближе к середине диапазона перемещения. Это означает, что для моделей гуманоидов предпочтительнее импортировать их в Т-образной позе.

../../_images/blending5.webp

Вы можете видеть, что приоритет отдается кратчайшему пути поворота от Bone Rest, а не кратчайшему пути поворота между анимациями.

Если вам нужно повернуть сам Skeleton3D более чем на 180 градусов, смешав анимацию движения, вы можете использовать Root Motion.

Корневое движение

При работе с 3D-анимацией популярной техникой является использование аниматорами корневой кости скелета для придания движения остальным частям скелета. Это позволяет анимировать персонажей таким образом, что шаги фактически соответствуют полу под ними. Это также позволяет точно взаимодействовать с объектами в кинематографе.

При воспроизведении анимации в Godot можно выбрать эту кость в качестве корневой дорожки движения ** . Это визуально отменит трансформацию кости (анимация останется на месте).

../../_images/animtree_rootmotiontrack.webp

После этого фактическое движение может быть получено через API AnimationTree как преобразование:

# Get the motion delta.
animation_tree.get_root_motion_position()
animation_tree.get_root_motion_rotation()
animation_tree.get_root_motion_scale()

# Get the actual blended value of the animation.
animation_tree.get_root_motion_position_accumulator()
animation_tree.get_root_motion_rotation_accumulator()
animation_tree.get_root_motion_scale_accumulator()

Это может быть передано в такие функции, как CharacterBody3D.move_and_slide для управления перемещением персонажа.

Также имеется узел инструмента RootMotionView, с помощью которого вы можете разместить сцену, которая будет выступать в качестве настраиваемого пола для вашего персонажа и анимаций (этот узел по умолчанию отключен во время игры).

../../_images/animtree15.gif

Контроль из кода

После построения дерева и его предварительного просмотра остается только один вопрос: "Как все это управляется из кода?".

Помните, что узлы анимации — это всего лишь ресурсы, поэтому они являются общими для всех экземпляров, использующих их. Установка значений непосредственно в узлах повлияет на все экземпляры сцены, которые используют AnimationTree. Это, как правило, нежелательно, но имеет несколько интересных вариантов использования, например, вы можете копировать и вставлять части своего дерева анимации или повторно использовать узлы со сложной компоновкой (например, StateMachine или пространство смешивания) в различных деревьях анимации.

Фактические данные анимации содержатся в узле AnimationTree и доступны через свойства. Просмотрите раздел "Параметры" узла AnimationTree, чтобы увидеть все параметры, которые можно изменить в режиме реального времени:

../../_images/animtree_parameters.webp

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

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

../../_images/animtree_propertypath.webp

Затем вы можете установить или прочитать их:

animation_tree.set("parameters/eye_blend/blend_amount", 1.0)
# Alternate syntax (same result)
animation_tree["parameters/eye_blend/blend_amount"] = 1.0

Примечание

Advance Expressions from a StateMachine will not be found under the parameters. This is because they are held in another script rather than the AnimationTree itself. Advance Conditions will be found under parameters.