Скриптинг анимации (Legacy)
Система анимации в Unity позволяет создавать великолепно анимированных персонажей. Она поддерживает блендинг, микширование, сложение анимаций, синхронизацию цикла ходьбы, анимационные слои, контроль всех аспектов проигрывания (время, скорость, веса блендинга), скиннинг мешей с 1, 2 или 4 костями на вершину, а также основанные на физике rag-dolls (тряпичные куклы) и процедурную анимацию. Для получения лучших результатов, рекомендуется почитать о практических подходах и принципах создания персонажей с оптимальной производительностью в Unity на странице Моделирование оптимизированных персонажей.
Создание анимированного персонажа включает в себя две вещи — перемещение в пространстве сцены и соответствующая анимация. Чтобы узнать больше о перемещении персонажа, прочитайте Character Controller page. На этой странице разбираются вопросы анимации. Фактически, вся анимация может быть сделана во встроенном редакторе Unity.
Вы можете попробовать примеры показывающие готовую анимацию персонажей. Чуть позже, когда вы освоите базовые вещи, можете взглянуть на описание класса Animation.
Смешивание анимации
В современных играх, смешивание анимации является необходимой функцией для обеспечения персонажа плавными анимациями. Аниматоры создают отдельные анимации, например, цикл ходьбы, цикл бега, анимация в состоянии покоя или стрельбы. В любой момент во время игры, должна быть возможность перехода с анимации спокойствия в цикл ходьбы и обратно. Естественно, вы хотите чтобы этот переход был плавным и без внезапных рывков в движении.
В этом случае смешивание анимации становится полезным. В Unity можно иметь любое количество анимаций, которые проигрываются на одном и том же персонаже. Все анимации смешиваются или складываются вместе для создания окончательной анимации.
Сначала сделаем плавный переход между анимациями спокойствия и ходьбы. Чтобы облегчить работу написания скрипта, сперва нужно изменить Wrap Mode анимации на Loop . Затем нужно отключить Play Automatically для уверенности, что никто, кроме нашего скрипта, не проигрывает анимацию.
Наш первый скрипт для анимации персонажа довольно простой; нам нужен способ для определения скорости движения персонажа, а после этого делать переход между анимациями ходьбы и покоя. Для этого простого теста мы будем использовать стандартные оси ввода:-
Чтобы использовать этот скрипт в вашем проекте:-
- Создайте Javascript файл используя Assets->Create Other->Javascript .
- Скопируйте и вставьте код в него.
- Перетащите скрипт на персонажа (он должен быть привязан к GameObject , который имеет анимацию).
После нажатия на кнопку Play, персонаж начнет шагать на месте, пока вы будете удерживать нажатой кнопку со стрелкой вверх, и вернется в позу ожидания, если вы отпустите ее.
Слои анимации
Слои это невероятно полезная концепция, позволяющая классифицировать анимацию и приоритезировать веса.
Система анимации Unity может смешивать несколько анимаций, в соответствие с вашими пожеланиями. Вы можете назначить веса вручную, или просто использовать animation.CrossFade() , который будет анимировать вес автоматически.
Веса смешивания всегда нормализуются перед применением
Предположим, что у вас есть цикл ходьбы и цикл бега, имеющие веса, равные 1 (100%). Когда Unity генерирует окончательную анимацию, веса нормализуются, то есть вклад цикла ходьбы составит 50% анимации, и вклад цикла бега также составит 50%.
Типично, вам захочется указать, какая анимация получает больший вес, когда проигрывается две анимации. Конечно, можно вручную убедиться, что веса суммируются в 100%, но легче просто использовать для этого слои.
Пример использования слоев
В качестве примера, вы можете использовать анимации стрельбы, ожидания и цикличной ходьбы. Анимации ходьбы и ожидания будут смешаны в зависимости от скорости игрока, но, когда игрок должен стрелять, вы хотели бы воспроизводить только анимацию стрельбы. Поэтому, фактически, анимация стрельбы имеет более высокий приоритет.
Самый простой способ добиться этого, это просто продолжать проигрывание анимаций ходьбы и покой во время стрельбы. Чтобы это сделать, нам надо удостовериться, что анимация стрельбы находится в верхнем слое над анимациями покоя и ходьбы, что означает, что анимация стрельбы будет получать веса смешивания в первую очередь. Анимации ходьбы и покой будут получать веса только если анимация стрельбы не использует все 100% веса. Так, когда начинается переход в анимацию стрельбы, вес начнется с нуля, и за короткое время станет 100%. Вначале, слой ходьбы и покоя все еще будет получать веса, но когда полностью закончится переход в анимацию стрельбы – они не получат веса вообще. И это в точности то, что нам нужно!
По умолчанию, animation.Play() и animation.CrossFade() остановят или плавно уберут анимации находящиеся в одном том же слое. Это то что требуется в большинстве случаев. В нашем примере стрельбы, покоя и бега, проигрывание покоя и бега не будет влиять на анимацию стрельбы, и наоборот (если требуется, то это поведение можно изменить опциональным параметром функции animation.CrossFade).
Смешивание анимаций
Смешивание анимаций позволяет урезать количество анимаций, который нужно создать для вашей игры. Это достигается тем, что некоторые анимации влияют только на часть тела. Это значит, что такие анимации могут быть использованы совместно с другими анимациями в разнообразных комбинациях.
Добавление трансформации смешивания анимаций производится вызовом метода AddMixingTransform() имеющегося AnimationState.
Пример смешивания
В качестве примера смешивания можно привести что-то вроде анимации махания рукой. Вы можете захотеть сделать махание рукой либо когда персонаж находится в покое, либо когда он идет. Без смешивания анимаций, вам бы пришлось сделать отдельные анимации махания рукой для состояния покоя и ходьбы. Но если вы добавите трансформацию плечей как трансформацию смешивания в анимацию махания рукой, то она будет иметь полный контроль только от плечевого сустава до руки. Так как остальное тело не будет подвержено влиянию анимации махания рукой ,оно продолжит играть анимацию покоя или ходьбы. Как следствие, понадобится только одна анимация, чтобы сделать махание рукой, тогда как остальное тело будет использовать анимацию покоя или ходьбы.
Другой пример с использованием путей.
Аддитивные (additive) анимации
Аддитивные анимации и технология смешивания анимаций позволяют уменьшить общее количество анимаций, которые вам надо создать для вашей игры, и эти техники также важны для создания лицевой анимации.
Предположим, вам захотелось создать персонажа, который наклоняется в стороны во время поворотов, когда он ходит или бегает. Это приводит к 4 комбинациям (идти-наклоняться-влево, идти-наклоняться-вправо, бежать-наклоняться-влево, бежать-наклоняться-вправо), для каждой из которых нужна анимация. Создание отдельной анимации на каждую комбинацию, очевидно, ведет к множеству дополнительной работы, даже в таком простом случае. Но количество комбинаций увеличивается с каждым добавляемым действием. К счастью, аддитивные анимации и смешивание позволяет избежать необходимости создания отдельных анимаций для комбинаций простых движений.
Пример аддитивной анимации
Аддитивные анимации позволяют накладывать эффекты одной анимации поверх любых других запущенных анимаций. Когда генерируются аддитивные анимации, Unity вычислит разницу между первым и текущим кадрами анимационного клипа. Затем разница применится поверх всех остальных проигрываемых анимаций.
Ссылаясь на предыдущий пример, вы могли бы создать анимации для наклонов вправо и влево, и Unity смог бы наложить их на цикл ходьбы, покоя или бега. Это может быть достигнуто с помощью кода следующим образом:-
Совет: При использовании аддитивных анимаций, очень важно также проигрывать какие-то другие не-аддитивные анимации на каждой трансформации, которая также используется в аддитивной анимации. В противном случае, анимации будут добавляться поверх результата последнего кадра. Это точно не то, что вам нужно.
Процедурная анимация персонажей
Иногда вам понадобится анимировать кости вашего персонажа процедурно. Например, вы хотите чтобы голова вашего персонажа смотрела в определенную точку в 3D пространстве. Это действие лучше всего реализовать с помощью скрипта, который отслеживает целевую точку. К счастью, Unity делает это очень простой задачей, так как кости всего лишь являются трансформациями, которые управляют кожей (skinned mesh). Вы можете управлять костями персонажа из скрипта так же, как трансформациями GameObject.
Одна из важных вещей, которую необходимо знать, это то, что анимационная система обновляет трансформации после функции Update() , и до функции LateUpdate() . Поэтому, если вам нужно вызвать функцию LookAt() , следует делать это в LateUpdate() , чтобы удостовериться, что вы на самом деле переопределяете анимацию.
Тряпичные куклы (Ragdolls) создаются таким же способом. Вам просто требуется добавить компоненты Rigidbody, Character Joint и Capsule Collider к различным костям. Это позволит вам создать анимацию вашего персонажа основанную на физике.
Воспроизведение и cэмплирование анимации
Этот раздел рассказывает о том как в Unity происходит сэмплирование анимации во время ее воспроизведения движком.
Анимационные клипы обычно являются фиксированными по частоте кадров. Например, вы можете создать анимацию в 3ds Max или Maya с частотой 60 кадров в секунду (FPS). При импорте анимации в Unity, частота кадров будет прочитана импортером, так что данные импортируемой анимации также будут 60 кадров в секунду (FPS).
Игры обычно работают с переменной частотой кадров. Частота кадров на вашем компьютере может быть выше, чем на других, и также может меняться из-за сложности отрисовки объектов в поле зрения камеры. В основном, это означает, что мы не можем сделать никаких предположений, с какой частотой кадров будет работать игра. Это значит, что даже если анимация создавалась для 60 кадров в секунду, она может быть воспроизведена на другой частоте кадров – например, 56.72, или 83.14 кадров в секунду, или любой другой.
В результате, Unity должен сэмплировать анимацию с различной частотой кадров, и не может гарантировать частоту кадров, для которой анимация создавалась. К счастью, анимации для 3D графики состоят не из дискретных кадров, а из непрерывных кривых. Так что, если игра выдает большую частоту кадров, чем частота кадров анимации, анимация будет выглядеть плавнее в игре, чем она выглядела в анимационном ПО.
Для большинства практических применений, можно игнорировать тот факт, что Unity сэмплирует анимацию на плавающей частоте кадров. Однако если присутствует игровая логика, которая опирается на анимации, которые анимируют трансформации и свойства в очень конкретные конфигурации — то вам нужно знать, что за кулисами применяется ресэмплинг. Например, если у вас есть анимация, которая поворачивает объект от 0 до 180 градусов за 30 кадров, и вы хотите знать из кода, когда была пройдена половина пути, вам не следует делать это с помощью условного выражения в коде, которое проверяет, что текущее вращение равно 90 градусам. Так как Unity сэмплирует анимацию на плавающей частоте кадров игры, сэмпл может быть взят когда вращение немного меньше 90 градусов, а следующий сэмпл — когда вращение немного больше 90 градусов. Если вы хотите получить нотификацию, когда была достигнута конкретная точка в анимации, следует использовать AnimationEvent (Анимационное событие).
Туториал 4: 2Д платформер (для новичков). Часть 1.
void FixedUpdate () <
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis ( «Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>
5. Step
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour <
//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent < Rigidbody2D > ();
>
//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if ( Input .GetButtonDown ( «Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce ( Vector2 .up * jumpForce, ForceMode2D .Impulse);
//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>
void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis ( «Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
>
>
6. Step
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour <
//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;
void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent < Rigidbody2D > ();
>
//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if ( Input .GetButtonDown ( «Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce ( Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>
void FixedUpdate () <
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis ( «Horizontal» );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;
//проверка, совпадает ли направление взгляда с направлением движения
if (x < 0 && !isLookingLeft)
//вызов функции поворота крысы, если проверка совпала
TurnTheRat ();
//проверка, совпадает ли направление взгляда с направлением движения
if (x > 0 && isLookingLeft)
//вызов функции поворота крысы, если проверка совпала
TurnTheRat ();
>
//функция поворота крысы
void TurnTheRat ()
<
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
>
7. Step
8. Шаг
9. Шаг
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAnim : MonoBehaviour <
//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
void Start () <
//делаем ссылку на аниматор
anim = GetComponent < Animator > ();
//делаем ссылку на Rigidbody2D
rb = GetComponent < Rigidbody2D > ();
>
void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х
anim.SetFloat ( «speed» , Mathf .Abs (rb.velocity.x));
>
>
10. Шаг
11. Шаг
12. Шаг
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAnim : MonoBehaviour <
//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;
void Start () <
//делаем ссылку на Animator
anim = GetComponent < Animator > ();
//делаем ссылку на Rigidbody2D
rb = GetComponent < Rigidbody2D > ();
//делаем ссылку на PlayerMove
pm = GetComponent < PlayerMove > ();
>
void Update () <
//проверка, находится ли крыса на земле
if (pm.isGrounded) <
//меняем параметр isJumping на false
anim.SetBool ( «isJumping» , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat ( «speed» , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
> else <
//меняем параметр speed на 0
anim.SetFloat ( «speed» , 0 );
//меняем параметр isJumping на true
anim.SetBool ( «isJumping» , true );
>
>
13. Step
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerSound : MonoBehaviour <
//ссылочная переменная для звукового файла
public AudioClip footsteps;
//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>
14. Шаг
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerSound : MonoBehaviour <
//ссылочная переменная для аудио-файла
public AudioClip footsteps;
//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
//запустится если было касание другого Collider2D
void OnCollisionEnter2D ( Collision2D coll) <
//проверка тэга на тэг «Ground»
if (coll.gameObject.tag == «Ground» ) <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>
15. Шаг
Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets). Поместите prefab Ground в сцену, как следующую платформу.
Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat). Камера будет следовать за крысой.
Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).
Работа с 2d анимациями (Actors, Unity) #2
Трудно представить современную игру без анимаций. Сегодня я расскажу о том как работаю с 2д анимациями на Юнити через фреймворк Actors. Описанный мною подход реализуется легко на любых движках и языках. Ну а проект на юнити можно скачать отсюда.
Проблема
Зачем свое решение писать если в Unity уже есть Mecanim? Я много работаю с 2д анимациями и могу ответственно сказать, что использовать меканим для 2д это как стрелять из пушки по воробьям. Много ассетов,много абстракций, много оверхеда, много гибкости и мало смысла.
Дело вкуса и предпочтений но для того чтобы настроить простейшие связи анимаций нужно
- Добавить animator на объект
- Сделать animator controller ( особенно жесть если анимация всего 1 или 2 ).
- Понять, что лучше для этих целей использовать component animation. Который Legacy. Который в общем-то не дает нам ничего кроме массива анимаций и проигрывания. Да еще и с лишними вызовами методов со стороны движка хрен знает чего и для чего.
Допускается что мы будем использовать и Animator Controller и Component Animation и работать уже с двумя логическими единицами - Нужно создать anim clip и загрузить туда свою 2д анимацию. Кто этим никогда серьезно не занимался не прелставляет какой это гемор. Спасает разве что PowerSprite Animator от Powerhoof.
- Настроить animator controller закончив это дело настоящим итальянским болоньезе,с кучей второстепенных скриптов и невнятной логики.
- Goto 1. и так пока весь проект незавалится кучей бесмысленных ассетов с animator и anim clip.
БОЛОНЬЕЗ НЯМ

Я не говорю, что mecanim плох, я говорю вот об этом:

Описываем задачу
Чертить тонны схем и из какого места должны вылазить методы не моё , но прежде чем погрузиться в код надо хотя бы примерно представлять что мы будем делать.
- Мы создаем систему которая будет работать БЕЗ юнити аниматора и анимклипов.
- Нам нужно иметь возможность загружать несколько анимаций для объекта.
- Нам нужен функционал позволяющий проигрывать цепочку анимаций. Хотя бы цепочку из двух анимаций.
- Было бы неплохо при вызове анимации получить назад время на проигрывание выбранной анимации.
- Нам нужно иметь возможность работать с анимациями через скрипты если это потребуется.
- Простое api чтобы назначать и сбрасывать анимации у сущностей.
- Работает из Actors разумеется.
Что мне нравится в системах анимаций так это то, что их можно сделать какими угодно сложными или простыми.
В конечном итоге у нас должно получиться что-то такое:
Я не следую общепринятым нотациям стиля для C#, пишите как вам больше нравится.
sequence
По-русски последовательность. Она и в Африке последовательность. Это аналог animclip
Здесь указываем массив спрайтов, ID следующей анимации если такая есть и даем возможность вытащить спрайт по индексу. Обычно я не люблю пользоваться свойствами в C#, но тут оно красиво позволяет обратиться к спрайту sequence[index]
sequences
Итак, у нас есть данные анимации, но нам надо их где-то хранить и обращаться к ним по ключу.
Кажется, словари C# идеальный кандидат на контейнер наших анимаций но. зачем если задачу можно решить проще? Массив с перебором гораздо компактнее и отлично подойдет для нашей несложной 2д игры. 100 анимаций никто ведь добавлять на объект все равно не будет.
Нам нужны ID для анимаций. Я предпочитаю использовать константы, но это так же легко делается через enum.
ComponentAnimator
Это компонент для екс. В общем-то это то что мы будем вешать на наши сущности.
Здесь нам интересен AnimatorGuide. Именно он позволит тонко работать с анимациями и добавлять к ним «события» и «скрипты».
AnimatorGuide
AnimatorGuide это аналог Mecanim в коде. С помощью animator guide можно легко настроить логику для базовых анимаций. Например все юниты проигрывают idle если скорость = 0 или меняют анимацию на бег если скорость выше 0.
AnimatorGuide по умолчанию не делает ничего. Напишем AnimatorGuidePawn который прикажет всем сущностям у которых он есть стоять на месте. Каждый раз когда мы создаем новую сущность она начнет проигрывать idle. Если мы в коде игры ( например в АИ скриптах ) перезапишем анимацию, то cAnimator.overriding не даст работать методу handle в AnimatorGuide. Так же нам не придется создавать по копии класса AnimatorGuidePawn для каждого юнита. Можно будет просто повесить один и тот же AnimatorGuidePawn через Instance.
ProcessorAnimator
Создаем процессор ( или еще их называют системами ) который будет обрабатывать все сущности с нашими компонентами ComponentAnimator и ComponentRenderer. ComponentRenderer просто хранит ссылку на SpriteRenderer.
game.locals.time_between_frames хранит время через которое нам надо обновлять кадры. В целях простоты мы не делаем локального времени для каждой отдельной секвенции, однако добавить это очень просто.
Осталось прикрутить API и сделать загрузку анимаций.
Метод ниже позволяет проиграть анимацию у сущности. Мы выбираем тип анимации, сколько раз она должна проиграться и c какого кадра. Мы так же считаем время нужное на проигрывание анимации и кешируем его в компоненте/возвращаем обратно.
anim.loop и anim.random_frame просто удобные константы чтобы указать что нам нужно сыграть анимацию бесконечно раз или нам нужен случайный кадр. Эти контанты добавляем к структуре anim«`
Последний метод который нам понадобится это animationReset Мы просто сбрасываем кадры до нуля и говорим, что больше не перезаписываем анимацию чтобы наш animator guide мог решить сам какую анимацию нужно запустить.
Загрузка анимаций
Делаем все из кода. Просто и быстро. Box.Load это обертка Resources.Load в фреймворке с возможностью кеширования. Последняя секвенция интересная. Мы в ней пишем, что после проигрывания анимации Grab нужно проиграть анимацию Walk
Результат
У нас на руках простое, легкорасширяемое решение по анимациям. Зарисуем же чтонибудь на экране. В самом начале поста я показывал как у нас это будет выглядить в скриптах игры.
Интереснее всего этот отыгрыш. После четырёх отыгрышей anim.grab отыграется anim.walk так как мы ее указали в настройках анимации для этого юнита.
Проект на unity можно скачать здесь.
Это не самая совершенная система, но ее не сложно дополнить нужными фишками. Но хочется особенно подчеркнуть : keep it simple, code fast.
А как справляетесь с анимациями вы? Делитесь мыслями и идеями в комментариях, будет интересно почитать 🙂