Проблемы покадровой анимации в Unity и как их быстро решить

Покадровая анимация на спрайтах в Unity из коробки — это весело.

Проблемы покадровой анимации в Unity и как их быстро решить

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

Давайте сразу очертим ряд проблем, которые хотелось бы решить:

  • сложный механизм клипов;

  • не менее сложный механизм транзакций;

  • невозможность «подменять» спрайты для скинов или просто универсальных контроллеров.

Про это ужасно много разных видео и статей, но я расскажу про самый тривиальный способ написать свой «велосипед» анимации, которым обычно пользуюсь сам. Сразу скажу, что каких-то открытий тут не будет, это лишь занимательная заметка.

Хранение анимации

Прежде всего, нужно создать объект, который будет хранить кадры анимации. Ничего особо не придумывая, я создал предельно простой scriptable-объект.

public class SpritesLine : ScriptableObject { public Sprite[] sprites; }

Чтобы каждый раз не собирать спрайты по одному руками, я сделал не менее простой скрипт для создания скриптового объекта.

public class SpriteLineCreating : MonoBehaviour { [MenuItem("Assets/Create/Sprites line")] public static void CreateSpritesLine() { var asset = ScriptableObject.CreateInstance<SpritesLine>(); var sprites = new List<Sprite>(); foreach (var selected in Selection.objects) { if (selected is Sprite s) { sprites.Add(s); } } asset.sprites = sprites.ToArray(); ProjectWindowUtil.CreateAsset(asset, "Sprite Line.asset"); } }

Теперь достаточно выделить несколько спрайтов, нажать правую кнопку мыши и выбрать Sprite Line. Всё предельно просто.

Осталось прикрутить это всё к самим объектам.

Аниматор

Создадим компонент, который будет устанавливать спрайты в SpriteRenderer. Я не буду расписывать каждый кусок кода — просто выложу на него ссылку, там достаточно много комментариев. Ещё там лежит кастомный инспектор для удобства. Тут выделю просто важные моменты.

Во-первых, я сделал переменную _revalidate, чтобы не слишком часто дёргать SpriteRenderer. Если этого не делать, скрипт будет постоянно обращаться к полю sprite и постоянно подгуружать связанные с полем объекты. Чтобы это возымело какой-то эффект, на сцене должно быть несколько тысяч спрайтов, но лично мне так спокойнее. Лично у меня на M1 при 10 тысячах спрайтов в редакторе _revalidate стало вопросом 20 FPS.

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

Вообще, аниматор получился ужасно простым, и его легко доделывать под нужные вещи. Я, например, добавил ивент для окончания анимации, чтобы разрушать объекты, которые представляют просто эффекты. Выглядит в редакторе это тоже максимально простенько, но ведь не часто нужно что-то большее.

Проблемы покадровой анимации в Unity и как их быстро решить

Велосипеды — это плохо

Очевидно, что не всем нравится писать «велосипеды», и хочется что-то поддерживаемое. Относительно недавно (полгода как не в эксперименте, если быть точным) в Unity появился инструментарий для подмены спрайтов в клипах с поддержкой покадровой анимации. От аниматора уйти это не позволяет, но вводит инструментарий для всего, что описано выше. Если вам всё-таки нравится аниматор или просто тяжело с него слезать — это, возможно, ваш выбор.

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

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

6666
17 комментариев

Используем приблизительно такой же подход в Erra: Exordium. Недавно писали статью в инди группе. 

За обновление аниматора отвечает уже сам скрипт, который управляет той или иной сущностью. Например, враг создаёт в себе аниматор и в своем методе Update вызывает метод Update аниматора, а тот уже сам считает межкадровый интервал, чтобы сменить спрайт. Ну и спойлер, мы не используем нигде в скриптах стандартный метод Update Моно, вопрос оптимизации. Используем только  один Update. Как и метод Start.

В адрес поддержке данной статьи скажу так, свой аниматор для простой замены спрайтов это вопрос получаса. Расширять его можно на протяжении хоть всего проекта по факту конкретной задачи. Но вот выбирать такой подход нужно взвешено. 
Мы приняли решение не сразу. В итоге полностью отказавшись от стандартного аниматора. А со временем наш функционал оброс слоями, событиями и всяким. Но повторюсь, решение было принято осознано, шанс аниматора в коробке мы давали много раз.

5
Ответить

Спрошу здесь: в чем преимущества аниматора Unity перед, скажем, созданием и добавлением анимаций из blender? 

Ответить

Ну дык вопрос не корректный, что-то вроде "чем преимущество приготовления борща, над копанием картошки".
В блендере ты создаешь свои анимации, а в аниматоре юнити ты строишь FSM для управления ими.

7
Ответить

Animator это стейт машина, а в блендере анимируются сами состояния этой стейт машины, как я понимаю. Соответсвенно, не совсем корректное сравнение

Если сравнивать анимирование самих состояний, то да, в Юнити можно делать свои анимации костные (и не только). Тогда можно будет не только мэшем оперировать, но и переменными внутри компонентов Юнити, дочерними элементами и всем-всем-всем. Другое дело, что аниматор (в смысле человек) должен будет освоить инструментарий Юнити

3
Ответить

Писать свой аниматор - довольно спорное решение. Если все анимации, которые будут в игре, требуют лишь простой смены спрайтов по времени - тогда вопросов никаких. В это случае намного лучше и проще написать маленькое решение, с которым будет намного проще работать, нежели с неудобным стандартным от Unity. Однако как только в ваших анимациях появляются дополнительные объекты, необходимость в прерываниях, переходах по условиям, событиях и прочем, то время затраченное на написание своей системы анимации далеко не факт что окупится в итоге. Потому что это все потребует и своих форматов, и системы работающей с этими форматами, так еще и UI для этого дела. Не "вручную" же эти все вещи создавать. А с UI и общим пайплайном становится все еще хуже, если работать с этим инструментом будет не только автор.

1
Ответить

Поэтому в конце расписал другие варианты

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

Ответить

Дополнение для работы с покадровой анимацией от создателя Crawl https://youtu.be/2_3xrqjTyes
https://assetstore.unity.com/packages/tools/sprite-management/powersprite-animator-71177 

1
Ответить