Эта заметка про разработку игр на движке Unity. В ней я расскажу как легко создать, изменить и анимировать персонажа. Затем использую полученные результаты в своей игре.
Создание модели гуманоидного персонажа и его анимаций
Для создания тела персонажа я воспользуюсь бесплатной программой Fuse. Скачать её можно бесплатно в Steam. Программа интуитивно-понятная, жаль давно не поддерживается. Есть и другие аналогичные программы (DAZ Studio, Poser, MakeHuman и другие). Идея таких программ заключается в генерации тела персонажа и одевании его; в некоторых можно сразу придать позу или применить анимацию.
После того как тело персонажа создано, экспортирую персонаж в папку. Если человечек будет маленьким, то желательно снизить качество текстур для кожи и каждого предмета одежды.
Далее придам персонажу немного индивидуальности в бесплатной программе Blender (кстати скачать её можно тоже в Steam). Программа довольно крутая, но сложная. Если кто хочет научиться, то вот тут мне понравилось как парень объясняет.
Загрузить персонажа в Blender можно с помощью меню Import->Wawefront(.obj). Карты Albedo и Specular накладываются, поэтому модель выглядит прозрачной - ничего страшного, просто пока игнорируем. Добавляем и меняем всё, что нам хочется, затем экспортируем модель. Мне нравится формат FBX (я ставлю отметки Selected Objects и Embed Textures в Path Mode = Copy).
Если будете рисовать персонажа сразу в Blender'e, не забудьте, что его следует держать в T-позе.
Далее зайду на сайт Mixamo, для этого придётся зарегистрироваться в сервисах Adobe, но ничего сложного. Там всё также интуитивно понятно.
Экспортирую в формате FBX for Unity те анимации, которые мне нужны (Without Skin) и в T-Pose (With Skin).
Импорт модели и анимаций в Unity
Создам в Unity в папке Assets папку Prefabs, а в ней папку с именем персонажа. Перенесу в эту папку все экспортированные из Mixamo анимации. Модель будет иметь только T-Pose, причём видно что текстуры упакованы только для тех частей, которые были дорисованы и раскрашены в Blender'e. Чтобы вернуть их на место перенесу в эту же папку все текстурные карты, которые появились при экспорте из Fuse. Unity спросит про карты нормалей, надо согласится кнопкой "Fix Now". После этого фигурка в предпросмотре станет раскрашенной как надо.
Теперь настрою каждую анимацию отключив ненужное на вкладке Model (на иллюстрации) в инспекторе. Перед тем как уйти с вкладки не забывайте жать кнопку "Apply". На вкладке Rig для модели со Skin'ом (T-Pose) выберу тип Humanoid, а в пункте Avatar Definition выберу "Create From This Model". Для других анимаций там же выберу Copy From Other Avatar и в Source выберу создавшийся автоматически аватар из T-позы.
Я буду двигать персонажа из программного кода, поэтому буду блокировать Root Transform Position для всех анимаций. Для анимаций бега и ходьбы я поставлю галочку "Loop Time". Если анимации планируется зациклить, но их начало и конец не совпадают, то надо сдвинуть время на шкале анимации так, чтобы поза начала и конца анимации была похожей (тогда загораются зелёным лампочки "loop match"). Если в предпросмотре анимации будет пусто или будет стандартная кукла, тогда с помощью бирюзового значка аватара надо выбрать свой. Окно предпросмотра по-умолчанию свёрнуто и развернуть его можно просто потянув за "полосочку" вверх мышкой.
Смена состояний персонажа и его анимации
Сменой анимаций в зависимости от ситуации будет управлять Animator Controller (я его создам в той же папке кликнув правой кнопкой мыши и выбрав из контекстного меню). Animator Controller является машиной состояний (детерминированным конечным автоматом) в максимально простой и интуитивно понятной реализации. Таким образом персонаж будет всегда находится в каком-то состоянии, а при переходе его в новое состояние будет запускаться настроенная нами анимация.
Настройка Animator Controller'a
Чтобы настроить Animator Controller надо перейти во вкладку Animator, она по-умолчанию закрыта и открыть её можно в меню Window->Animation->Animator, а затем закрепить в удобном месте. Кликнув на Animator Controller'e во вкладке Animator откроется пустое поле с тремя состояниями: AnyState, Entry и Exit. Я выделю и перенесу на это поле все анимации, кроме T-Pose. Для удобства расставлю анимации и AnyState кружком.
Затем нажму правой кнопкой мышки на состоянии Entry и выберу "Set StateMachine Default State" (появится стрелочка от Entry к курсору мышки), затем кликну на анимации ходьбы. Чаще всего начальная анимация будет просто "стоять на месте". Таким образом у меня персонаж как только появится в сцене уже будет идти (как я выбрал чуть выше: бесконечно долго и на месте).
Переходы от анимации к анимации могут происходить по окончанию предыдущей (например поднял камень и совершил бросок) либо по наступлению какого-то события (например персонаж поднял камень и ждёт пока игрок нажмёт кнопку броска). Я буду управлять переходами из состояния в состояние (а следовательно и анимациями) из программного кода, поэтому для начала создам (кнопочкой с плюсиком) во вкладке Parameters окна Animator триггер для перехода к состоянию атаки и назову его "ToAttack".
Кликнув правой кнопкой мыши на состоянии ходьбы выберу "Make Transition" и проведу стрелочку к анимации удара. Далее нажму на стрелочке перехода, чтобы она выделилась. При этом в инспекторе появились настройки перехода (плавность), а в предпросмотре сразу можно посмотреть как это выглядит.
Но если захочется, чтобы анимация начиналась резко (после любых анимаций), то можно вести стрелку перехода от AnyState. В самом состоянии можно подключить скрипт, в котором можно например применять какие-то эффекты. Что может быть удобно для переходов по окончанию предыдущей анимации.
Создание префаба персонажа
Переходы настроил пока приблизительно - потом всегда можно будет вернуться к этому. Но новые анимации лучше заготовить впрок даже если они возможно и не пригодятся, так как их можно будет сделать в Mixamo только до тех пор, пока модель персонажа не заменена там другой. После того как я сделал все переходы, которые мне хочется надо создать префаб персонажа. Для этого я перетащу анимацию с T-Pose на сцену (при этом в иерархии создастся префаб), там выставлю начальное положение и масштаб. В поле компонента Animator этого префаба перетащу настроенный недавно Animator Controller.
Затем я перетащу префаб персонажа из иерархии обратно в папку (создам в ней Original Prefab).
Есть случаи когда анимация начинается и заканчивается в разных местах, а хочется, чтобы персонаж при этом не смещался (так как управляется его движение из скрипта). Если включена галочка Loop Time (повторять анимации до тех пор пока не изменится состояние) становится доступной галочка Loop Pose (плавно возвращать назад смещающегося персонажа). Но в динамичных анимациях с неравномерным смещением это выглядит ужасно. Тогда можно на префабе (с контроллером анимации) в инспекторе включить галочку "Apply Root Motion", тогда модель будет смещаться согласно анимации. Но если смещения не надо, то можно возвращать одновременно с этой анимацией - другой, запущенной одновременно (либо изменением transform.localPosition из скрипта, прикреплённого к самой анимации).
В иерархии (и соответственно на сцене) удалю этот префаб, а вместо него создам пустой объект (с помощью кнопки с плюсиком и там Create Empty) и задам ему начальную координату. Этот пустой объект я тоже перетащу в папку (создастся пустой префаб) и переименую в хорошее название. Со сцены теперь его можно удалить, либо там и оставить (смотря в каком месте и в какой момент этот персонаж у Вас появляется). Далее я открою этот пустой префаб двойным кликом (или кнопкой Open Prefab), иерархия при этом станет чистой. Затем перетащу в иерархию префаб, созданный из анимации T-Pose с моделью, контроллером анимации и настройками поворота и масштаба. Вернуться к сцене можно стрелочкой назад в иерархии.
Все эти манипуляции нужны мне были для реализации следующей идеи: Сделав таким образом несколько персонажей или NPC я могу выставлять их в нужные места, вращать и масштабировать без учёта размеров и ориентации модели, так как их масштаб по осям координат всегда будет (1,1,1), а смещение относительно положения ступней (0,0,0).
Если скрипт управления персонажем будет подключен к префабу верхнего уровня, то для переключения анимации и движения я поступлю так:
[RequireComponent(typeof(Rigidbody))]
...
private Animator _animator;
private Rigidbody _rb;
...
private void Start() {
_rb = GetComponent<Rigidbody>();
_animator = GetComponentInChildren<Animator>();
...
_animator.SetTrigger("ToIdle");
_rb.velocity = Vector3.zero; //_rb.velocity = transform.forward * RUN_SPEED;
_________________________________________
Если Вам была полезна эта статья, то возможно будет интересно узнать про загрузку сохранений из файла и смену языка интерфейса в игре на движке Unity. В следующей статье про Unity я расскажу про интеграцию с планировщиком задач Jira и системой контроля версий GitHub.
#unity3d #машина состояний #анимация персонажа #3d графика #разработка игр