Дневник разработки Erra: Exordium #2: Покадровая анимация, код и велосипед
Всем привет. На связи Fair Pixel. В этот раз мы расскажем про анимации в проекте Erra: Exordium. О том как они повлияли на геймплей и на каком велосипеде мы едем.
Поначалу мы хотели видеть игру неспешной, в угоду эксплорингу. Первый год разработки мы шли по этому пути, попутно создавая внутри игры различные ситуации. Это позволяло понять какие геймплейные ситуации мы хотим дать игроку.
Но с каждым новым механом ускорялся темп геймплея. Приходилось вносить изменения в анимации главного героя. Менялся персонаж. А его визуальное поведение начинало влиять на буквально всё.
Вслед за героем претерпели видимых изменений противники, как в плане движений, так и в плане видимой атаки. Но о противниках мы расскажем в другом выпуске нашего дневника.
Это лишний раз показывает важность предпродакшна и четкого видения геймплея.
А теперь про велосипед “Аниматор”
Без купюр и возможно с позором. В главных ролях: Unity Animator, программисты Fair Pixel.
За кулисами эволюции персонажа, а именно анимациями, есть небольшая история технической части проекта. Так как каждая наша анимация состоит из полностью прорисованных кадров, а в анимациях нет вращений объектов, мы решили, что управлять этим будет проще паренной репы. Ведь есть Animator и всякие там связи, переходы, вызовы методов класса. Вы и сами знаете, как это всё работает.
Первый Pipeline был следующим: художник давал кадры программисту или сам собирал их в анимацию в Unity (просто набор последовательных кадров, иногда с разным межкадровым интервалом), а программист добавлял анимацию в аниматор и настраивал связи.
Количество анимаций росло. Усложнялись состояния. Увеличивалось количество переходов. Это привело нас к тому, что кадры анимаций стали анимациями в аниматоре. И тут ты наверное крутишь палец у виска?!
То ли из-за отсутствия опыта, то ли из-за страха перед увиденным, мы решили, что для нас стандартный Unity Animator слишком шикарен.
Во-первых, мы начали тратить на это много времени. Настройка, отладка - это ещё полбеды. Расширение анимации, логики, вызовы кода, более сложные штуки - вот это была боль.
Во-вторых, мы решили отделить руки с огнестрельным оружием от тела, чтобы не рисовать всего персонажа целиком с оружием на каждый вид состояния. Представь себе, что персонаж с пистолетом может целится стоя, сидя, в движении. И оружие при этом не крутится как объект. Отдельное положение оружие - это конкретный кадр. Типа трупиксель! А потом ещё доставать оружие, прятать, перезаряжать и опять стоя, сидя, в движении… Прогрессия!
Поэтому было решено написать свой велосипед. Который был бы проще в настройках и решал бы вот всё выше написанное. В итоге информация про анимацию хранится в контейнере (благодаря ScriptableObject) и описана тремя полями: идентификатор, межкадровый интервал и набор спрайтов.
Вначале был один класс управляющий анимацией. Его задачей было взять информацию про анимацию и просто переключать спрайты во времени.
С появлением новых требований, менялась архитектура. На данный момент часть архитектуры выглядит так:
AnimationManager находится в каждом персонаже. Он хранит и управляет слоями анимации. LayerController содержит в себе перечень всех анимаций слоя. Анимацией управляет AnimationController. Таким образом, данные анимаций из ScriptableObject превращаются в AnimationController, в котором присутствует набор команд и событий.
Приведем пример на псевдокоде.
В классе CharacterExample показана инициализация аниматора. AnimationManager получает доступ к компоненту объекта (SpriteRenderer) и данные анимации. StateManager сегодня мы обсуждать не будем, кратко скажем, что это машина состояний для разных живых объектов в игре.
Класс IdleState демонстрирует простой вызов смены анимации при старте состояния Idle.
Класс JumpState демонстрирует варианты вызовов и события анимаций. При запуске состояния, аниматор переключится на анимацию JUMP. Затем произойдет переключение на анимацию JUMP_MOTION, когда сработает условие в событии FrameHandler. По завершению той или иной анимации, сработает переход в состояние IDLE. Ещё раз повторим, что это псеквдокод… Простая демонстрация некоторых возможностей.
Таким образом, нам удалось получить полный контроль над анимациями, их отображением и корректировкой геймплея, чтобы не происходило “разрывов” и прочих неприятных вещей.
И вот мы "победили", казалось бы, такую небольшую, но такую важную вещь. Зато теперь живем в мире и согласии с кодом и анимациями.
Нам будет очень интересно выслушать ваши примеры решения собственных велосипедов. А может у вас есть советы как можно было решить нашу проблему.
Будем рады услышать каждого!
Это да, аниматор юнити не самый приятный товарищ.
не только нам так показалось?
анимации прикольные) желаю удачи)
Спасибо)