Альтернативные методы использования Animation Curves в Unity

Эта статья является адаптированным переводом видео с канала GameDev Guide. По Animation Curves в Unity относительно мало туториалов, поэтому я решил, что это видео стоит того, чтобы перевести его и сделать туториал в ру-сегменте.

Плюс, я сам активно пользуюсь Animation Curves в своём проекте, но об этом чуть позже.

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

Оригинальное видео

Вступление

Кривые повсюду. Мы можем видеть их в природе, в физике и, конечно, в анимациях. В анимации кривые делают движение более естественным и передают ощущение веса, в то время как равномерное "линейное" движение ощущается странно и неестественно.

Сверху - линейное движение, снизу - с применением кривых (ускорение и замедление)

Но с помощью Animation curves вы можете улучшить не только анимации. Я убеждён, что если у вас не получается сделать так, чтобы что-то ощущалось хорошо или числовые значения выглядят неверными, возможно, чтобы исправить это, вам просто надо использовать Animation curve.

Классическое применение анимационных кривых

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

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

Альтернативные методы использования Animation Curves в Unity

Большинство tweening-библиотек и плагинов (DOTween, iTween и т.д.) позволяют использовать эти пресеты, а также задавать произвольную кривую для изменения желаемого параметра.

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

Альтернативные методы использования анимационных кривых

Предположим, мы работаем над платформером и хотим, чтобы наш персонаж начинал двигаться с ускорением, пока не достигнет своей максимальной скорости.

Традиционный подход выглядел бы примерно так:

if (speed < maxSpeed) { speed += acceleration * Time.deltaTime; }

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

В качестве алтернативы разработчики могут вывести или найти формулу "интересной" анимационной кривой для ускорения, типа той, что приведена ниже.

x = x < 0.5f ? 16 * x * x * x * x * x : pow(2 * x + 2.5) / 2;

Но настройка параметров, визуализация и проверка результата может быть очень времязатратной.

Вместо этого мы можем использовать Animation Curves, чтобы избавить себя от этих неприятных моментов. Также мы сразу сможем визуализировать и настраивать кривую прямо в Unity.

Чтобы получить анимационную кривую в инспекторе Unity, нам нужно использовать специальный тип переменной.

public AnimationCurve movementCurve;

После этого анимационная кривая отобразится в инспекторе.

Альтернативные методы использования Animation Curves в Unity

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

speed = movementCurve.Evaluate(time); time += Time.deltaTime;

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

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

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

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

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

Альтернативные методы использования Animation Curves в Unity

Также, с помощью анимационных кривых, мы можем контролировать то, как камера будет двигаться из точки А в точку Б.

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

Альтернативные методы использования Animation Curves в Unity

Ещё более альтернативные способы использования анимационных кривых

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

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

Нелинейная зависимость уровня персонажа от общего количества полученного опыта.

Допустим, у меня есть класс персонажа с разными статами для RPG. Я хочу, чтобы уровень персонажа увеличивался по мере получения опыта. Но я не хочу, чтобы количество необходимого опыта менялось линейно, потому что, как я уже говорил раннее, это скучно и ощущается не очень хорошо. Я хочу, чтобы по ходу прокачки, игроку требовалось всё больше и больше опыта, чтобы поднимать уровень персонажа.

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

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

Альтернативные методы использования Animation Curves в Unity

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

Затем, таким же образом я получаю значение опыта для следующего уровня. Вычитая из него текущее количество опыта, получаем оставшееся количество опыта, для достижения следующего уровня.

Альтернативные методы использования Animation Curves в Unity

Теперь я могу использовать полученные значения, чтобы визуализировать прогресс персонажав интерфейсе на прогресс-баре.

Настройка нелинейной прогрессии.

Мы также можем создать Custom Editor и отображать каждый уровень с необходимым количеством опыта в инспекторе.

Альтернативные методы использования Animation Curves в Unity
Перфекционистам и любителям "красивых" чисел такой метод явно не подойдёт :)
Перфекционистам и любителям "красивых" чисел такой метод явно не подойдёт :)

При изменении анимационной кривой значения в инспекторе будут обновляться автоматически.

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

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

Ещё один метод использования кривых

Ещё кривые можно использовать буквально для рисования... кривых! Прямо в в сцене или в интерфейсе.

Мы можем передавать значения с кривой в LineRenderer и получать координаты каждой точки.

Альтернативные методы использования Animation Curves в Unity

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

От себя

Мне лично очень нравятся Animation Curves как инструмент и я тоже активно использую их в своём проекте. Хочу в дополнение к тому, что было рассказано в оригинальном видео, поделиться с вами ещё одним способом их применения.

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

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

Для настройки формы щупальца я использовал несколько анимационных кривых, передавая в качестве параметра удалённость точки от начала щупальца. С помощью анимационных кривых, в реальном времени можно настраивать следующие параметры:

  • Толщину щупальца
  • Степень скрученность спирали
  • Радиус спирали
  • Различные профили в зависимости от фазы (щупальце летит вперёд, щупальце возвращается, персонаж подтягивается на щупальце и т.д.)
Альтернативные методы использования Animation Curves в Unity

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

На практике это всё выглядит так:

Нелинейная настройка толщины, радиуса спирали и степени скрученности, в зависимости от длины щупальца.

На этом у меня всё. Надеюсь туториал был вам полезен. Если у вас есть вопросы или вы просто хотите поболтать про геймдев, заходите на мой Discord-сервер. Если у вас есть опыт нестандартного использования анимационных кривых, делитесь им в комментариях.

Спасибо за внимание!

7272
8 комментариев

Видел это видео ранее и... Твой пример с щупальцем единственный адекватный, и вообще отличный.

Все остальное, за исключением разве что отображения кривой - делается твинами. Зачем для движения камеры использовать анимационную кривую если есть отличный инструмент Cinemachine со всем встроенным функционалом - непонятно. Из разряда "строем свой велосипед разобрав готовый".

Анимационная кривая для кривой опыта - невероятная костыльная дичь. У автора в видео видно что цифровые значения рандомные, вместо какого-нибудь четкого инкремента +25%. И самое главное даже по гифке в статье видно что значения бешено скачут при малейшем движении тангенса. Хрен ты что таким образом настроишь.

4
Ответить

Согласен, что пример с прогрессией не самый удачный, но, как говорится, из песни слов не выкинешь :) Я лично предпочитаю подобные вещи делать формулами в экселе.

По поводу твинов тоже от части согласен. Но я часто слышал жалобы от художников, что им тяжело работать с твинами, потому что они не наглядные и им тяжело, например, представить разницу между InOutQuad и InOutQuart. Так что для них анимационные кривые могут быть более наглядным и удобным инструментом.

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

3
Ответить

Люблю эту штуку. Последнее, что на ней сделал - это скорость разгона мотоцикла (чтоб в начале разгоняется быстро, но чем быстрее едет, тем меньше ускорение) и имитация качания деревьев на ветру. Дёшево и сердито: зацикленный поворот по одной оси по кастомному закону.

3
Ответить

Добавлял это видео в прошлую подборку. Инструмент удобный. Но вот для других вещей (прогрессия, например), если и использовать, то как промежуточное звено. На выходе должен быть формат, который можно экспортнуть/импортнуть: json, csv и т. д. Это же часть баланса, а его обычно в каких-нить спредшитах заводят.

Ответить

Дико плюсую, обожаю кривые. Был у меня клиент из разряда, "пусть персонаж бежит быстро, через две секунды медленно, птом рывок, потом опять медленно и если не добежал до финиша, то пусть всё в обратном порядке".

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

Ответить

Так же их можно использовать вместо масивов или таблиц. И когда тебе клиент скажет что "а вот между вторым и третьем элементом нужно сделать плавный переход" кривые позволяют не послать заказчика на хуй.

Ответить

Тема функций движения всегда актуальна. Недавно наткнулся на один пример

Ответить