Узнайте, как использовать LeanTween для анимации пользовательского интерфейса и различных игровых объектов в Unity 3D, создав клон игры-арканоида Breakout.
Версия: C# 7.3, Unity 2020.3, Unity
При создании игр вам часто нужно анимировать элементы на экране, чтобы создать повествование или добавить особый блеск, чтобы заинтересовать игрока. В последнем случае единственная цель этих эффектов — сделать гэймплей приятным.
В Unity есть мощный и удобный анимационный движок, который позволяет анимировать все, что угодно. Однако некоторые типы анимации, особенно самые простые, не нуждаются во всей мощности анимационного движка. Вы можете выполнять их более эффективно с помощью более простого подхода: методов Tweening.
В этом уроке вы узнаете о твининге и о том, как:
- Использовать анимацию в игровых объектах, таких как ассеты и пользовательский интерфейс.
- Интегрировать пакет LeanTween в свой проект.
- Применять эффекты вращения, смещения и масштабирования к игровым объектам.
- Добавлять элементы пользовательского интерфейса в свои проекты.
К тому времени, когда вы закончите, вы будете думать об анимации не только с точки зрения Unity Animator, но и с использованием других типов пакетов. В качестве бонуса окончательный образец проекта будет выглядеть великолепно!
Приступая к работе
Нажмите кнопку «Скачать материалы урока» вверху страницы, чтобы скачать начальный проект. Для этого проекта требуется Unity 2020.3.20f1 или более актуальная версия.
В Assets/RW вы найдете ассеты, используемые в проекте. Посмотрите на структуру папок:
- Input: Файлы, используемые новой системой ввода Unity.
- Physics Materials: Физические материалы, используемые для мяча в проекте.
- Plugins: В этой папке установлен LeanTween. Позже в этом уроке вы узнаете, как установить LeanTween в свои проекты.
- Prefabs: Префабы проекта.
- Scenes: Здесь вы найдете образец сцены.
- Scripts: Скрипты C# для проекта.
- Sprites: Игровая графика, любезно предоставленная kenney.nl.
- Text Mesh Pro: Файлы, используемые Text Mesh Pro, где вы создаете пользовательский интерфейс. Чтобы узнать больше, обязательно ознакомьтесь с уроком по TextMesh Pro.
Сколько много папок!
Откройте сцену TweenBreaker в Assets/RW/Scenes, затем нажмите на Play, чтобы попробовать клон Breakout. Используйте стрелки вправо и влево или кнопки A и D на клавиатуре, чтобы перемещать ракетку-брусок. Заставьте мяч подпрыгивать и разбейте столько кирпичиков, сколько пожелаете.
Теперь пришло время поближе познакомиться с твининг-анимацией.
Почему бы не использовать Unity Animator для всего?
Это отличный вопрос!
В Unity уже есть модуль, способный реализовать большинство видов анимации, так зачем вам еще один пакет? Разве это не лишнее?
Ключевое слово здесь — излишне. Анимационный движок слишком мощен для более простых задач и может отнимать драгоценные ресурсы компьютера игрока.
Компонент Unity Animator имеет функцию обратного вызова, которая постоянно вызывает каждого аниматора на сцене. Анимация игровых объектов без использования компонента Animator — отличный способ снизить требования.
Что такое твининг?
Проще говоря, tweening или inbetweening (промежуточное положение) — это другое название интерполяции. В этой операции свойство может принимать любое значение между двумя пределами.
Например, представьте себе игровой объект, который перемещается между двумя точками с интервалом в четыре секунды, как показано на следующем рисунке:
Вы знаете положение в ноль секунд и четыре секунды: как показано на рисунке, это точки (0, 0, 0) и (1, 0, 0). Однако для правильной анимации компьютеру необходимо отрисовывать каждый кадр.
Получая значения между этими точками, анимационный движок может определить, что через две секунды игровой объект должен быть в (0.5, 0, 0), через одну секунду — (0.25, 0, 0), через три секунды — (0.75, 0, 0) и так далее. Эта простая интерполяция создает анимацию, используя только простые алгебраические операции.
Эту анимацию можно сделать немного красивее, используя кривые для анимации, также известные как tweening curves. В предыдущем примере, чтобы получить положение элемента в любой момент времени, вам нужно было разделить общее смещение на прошедшее время и прибавить это значение к исходному положению.
Это не единственный способ достичь конечного значения: прогресс не обязательно должен быть равномерным. Пришло время обсудить кривые анимации, также называемые функциями плавности.
В этом случае интерполяция больше не является линейной, а вместо этого использует произвольную функцию, определяющую, как движется элемент. Например, если вы сказали, что игровой объект в предыдущем примере должен двигаться аналогично синусоидальной функции, скорость будет ниже в экстремумах функции.
Дополнительные сведения о функциях плавности и их эффектах смотрите по этой ссылке.
Компонент Animator против методов Tweening
Когда вы выбираете между двумя методами, то должны учитывать сильные и слабые стороны анимации.
Твининговая анимация отлично подходит для простых компонентов и анимации. Хорошее эмпирическое правило — использовать анимацию всякий раз, когда вы хотите анимировать что-то простое, не жертвуя частотой кадров.
Но попытка создать сложную анимацию исключительно с помощью твининга может быстро выйти из-под контроля. Дополнительный объем и мощность компонента Animator лучше подходят для работы с этими более сложными анимациями, такими как спрайтовая или скелетная анимация.
Сколько затрат вычислительных ресурсов в компоненте Animator? Давайте сравним их производительность.
Сравнение производительности
Вы можете использовать профилировщик Unity, чтобы получить лучшее представление о том, что происходит за кулисами в этом аниматоре и сравнить его с твинингом. Для лучшего сравнения возьмем пример сцены со спрайтами, движущимися, как показано на следующем рисунке:
Теперь рассмотрим сцену, в которой многие из этих спрайтов совершают одно и то же движение. По мере увеличения их количества соответственно возрастают и требования к компьютеру. Для 300 спрайтов, движущихся боком вместе с аниматором, профайлер Unity показывает:
Эта толстая синяя линия показывает, сколько вычислительной мощности потребляет компонент Unity Animator. Выбор линии в заданной точке показывает, что происходит в основном цикле Unity:
Обратите внимание, что главный злодей здесь — метод Animator.Update()
. Этот метод занимает много времени обработки основного потока. Если бы только был способ избавиться от этого…
Вот где LeanTween имеет значение. LeanTween — это пакет, обеспечивающий простую и облегченную реализацию анимации движения. Без необходимости вызывать Animator весь процесс резко меняется. Посмотрите, что об этом говорит профайлер Unity:
Главный поток тоже другой. Посмотрите:
И финальный эффект анимации такой же. Эта демонстрация доказывает, что удаление компонента Animator из более простых анимаций позволяет повысить производительность и улучшить сложные анимации.
Добавление LeanTween в ваш проект
Чтобы добавить LeanTween в свои проекты, перейдите на его страницу в магазине ассетов и добавьте в свои ассеты.
Когда вы закончите, он появится в окне проводника пакетов в Unity. Выберите его и нажмите Install. При появлении запроса нажмите Import, чтобы добавить пакет в проект.
Теперь об использовании недавно добавленного пакета в вашей игре.
Анимация ракетки с помощью библиотеки Tween.
Первый игровой объект, который вы будете анимировать, — это ракетка-брусок. Изначально ракетка не реагирует на удары мяча, что не кажется реалистичным. В конце концов, когда объекты сталкиваются друг с другом в реальной жизни, всегда есть реакция.
Чтобы игрок почувствовал действие, брусок должен реагировать на столкновение. Вы будете использовать функции перевода для его соответствующего смещения.
Перемещение объектов с помощью LeanTween
Как вы уже узнали, твининг можно использовать для смещения игровых элементов на определенное время. В LeanTween функция перемещения заботится об общем смещении. Вы указываете начальную позицию, конечную позицию и время, которое должно потребоваться для движения.
Однако более специализированные функции перемещают игровой объект по одной оси: moveX
, moveY
и moveZ
. В этом уроке вы будете использовать функцию, предназначенную для перемещения бруска по оси Y.
Отскок бруска
Вам нужно добавить некоторое смещение весла и заставить его реагировать на столкновение с мячиком. Перейдите в Paddle.cs и замените весь метод OnCollisionEnter2D()
на:
private void OnCollisionEnter2D(Collision2D collision)
{
//1
if (collision.gameObject.tag.Equals("Cog"))
{
//2
LeanTween.cancel(gameObject);
//3
LeanTween.moveY(gameObject, transform.position.y - 0.5f, 0.5f).setEaseShake();
}
}
Этот код выполняет три основные функции:
- Эта строка проверяет, есть ли столкновение между бруском и мячом («шестеренка»). В этом примере брусок не может столкнуться ни с чем другим, но рекомендуется четко определить, какое столкновение вы хотите обрабатывать.
- Эта функция указывает LeanTween остановить любые другие эффекты, которые могут воздействовать на этот игровой объект. Такой шаг поможет вам избежать ошибок, гарантируя, что никакие другие эффекты анимации не будут работать одновременно с элементом.
- И наконец, это строка, которая действительно создает движение. Если бы это было предложение на обычном языке, то функция сказала бы «переместить ось Y игрового объекта на пол-единицы вниз в течение полсекунды».
Теперь нажмите кнопку воспроизведения. Вы увидите, как брусок подпрыгивает вверх и вниз в течение полсекунды, а затем возвращается в исходное положение.
Однако, несмотря на то, что брусок перемещается вдоль оси Y, в итоге он возвращается в исходное положение. Это происходит из-за setEaseShake()
, добавленного в конце LeanTween.moveY()
. Эта кривая замедления определяет, что движение должно заканчиваться в той же точке, где оно началось, создавая эффект отскока, показанный на бруске.
Если хотите, удалите код setEaseShake()
и посмотрите, как брусок заходит за нижнюю часть экрана. Но не забудьте добавить его обратно, когда закончите.
Добавление персонажа к мячу
В стартовом проекте мяч подпрыгивает, разбивая кирпичики и отскакивая от ракетки-бруска. Однако вы можете сделать его более интересным персонажем.
В настоящее время анимация мяча основана исключительно на физике: когда мяч сталкивается, он отражается и продолжает двигаться. Но с помощью анимаций вы можете сделать мяч более интересным.
Чтобы создать интересную графику, начните с изменения масштаба мячика с помощью эффектов твининга.
Масштабирование мячика
Все примеры до сих пор были о движении. Однако вы можете выбрать значение для любого данного свойства.
Чтобы проиллюстрировать эту концепцию, замените метод OnCollisionEnter2D()
в BallScript.cs на:
private void OnCollisionEnter2D(Collision2D collision)
{
if (collision.gameObject.tag.Equals("Player"))
{
hitPosition = (ballRigidbody.position.x - collision.rigidbody.position.x)
/ collision.collider.bounds.size.x;
direction = new Vector2(hitPosition, 1).normalized;
ballRigidbody.velocity = direction * BallSpeed;
}
// 1
LeanTween.cancel(gameObject);
transform.localScale = new Vector3(0.4f, 0.4f, 0.4f);
// 2
LeanTween.scale(gameObject, new Vector3(1.0f, 1.0f), 1.0f).setEase(LeanTweenType.punch);
}
Вот разбор кода:
- Эти две строки сбрасывают поведение игрового объекта. В дополнение к
LeanTween.cancel()
необходимо сбросить вес мячика, чтобы избежать распространения ошибок. Если мячик столкнется с другим элементом до окончания анимации, начальный масштаб будет неверным, а в конце изменится «обычный» размер мяча. - Опять же, это код, который фактически выполняет операцию. Однако на этот раз вы масштабируете игровой объект, а не перемещаете его. Это масштабирует мяч от его нормального размера (0.4) до 1.0 и обратно благодаря функции ослабления
punch
.
Нажмите на кнопку Play. Посмотрите, как красиво мяч себя сейчас ведет:
Персонализированные функции плавности
В этом примере вы использовали предопределенную кривую замедления для операции масштабирования. Но setEase
не ограничивается только кривыми смягчения LeanTweenType
.
Эта функция также дает вам возможность рисовать собственные кривые с помощью Unity. Добавьте следующую переменную animationCurve
в класс BallScript
:
public AnimationCurve animationCurve;
Затем замените:
LeanTween.scale(gameObject, new Vector3(1.0f, 1.0f), 1.0f).setEase(LeanTweenType.punch);
этим:
LeanTween.scale(gameObject, new Vector3(1.0f, 1.0f), 1.0f).setEase(animationCurve);
Сохраните изменения скрипта и перейдите в окно Hierarchy. Разверните игровой объект Player Objects, выберите игровой объект Cog и посмотрите в окно Inspector.
Вы увидите новый параметр, который позволит вам изобразить функцию плавности графически. Вы также можете выбрать предопределенную кривую, определенную Unity.
Это особенно полезно для тестирования, потому что вы можете попробовать различные кривые и поведение для элементов сцены в режиме воспроизведения. Вы можете настраивать свою игру так, как хотите, пока игра не будет выглядеть именно так, как вы хотите.
Например, если вы настроили кривую на быстрый подъем, вот так:
Сначала мячик быстро растет, а затем останавливается, вот так:
Однако, если кривая перевернута:
Мячик начнет медленно расти и набирать обороты:
Поскольку в коде вы устанавливаете масштаб мяча для сброса его масштаба при каждом столкновении, он будет работать с любой кривой, которую вы решите разработать. Однако, чтобы не полагаться на установку размера с помощью кода, вы можете попробовать кривую, которая возвращается к исходному размеру в конце после применения некоторого масштабирования, например:
Нажмите правой кнопкой мыши на кривую и добавьте столько ключей, сколько хотите, чтобы создать различные эффекты. Эта кривая придает мячу ощущение резины:
Теперь создайте свою собственную резиновую кривую и выберите ее в качестве кривой анимации для скрипта.
Эффекты изменения цвета
В дополнение к эффектам на основе преобразования, таким как движение и масштабирование, вы также можете добавлять эффекты изменения цвета.
В BallScript.cs добавьте еще одну строку в конец метода OnCollisionEnter2D()
, чтобы учесть цветовые эффекты:
gameObject.LeanColor(Color.yellow, 0.5f).setEasePunch();
Эта последняя строка заставляет мяч мигать желтым цветом в течение полсекунды, создавая следующий эффект:
В случае изменения цвета у вас есть возможность вызвать функцию LeanTween непосредственно для игрового объекта, а не передавать игровой объект в качестве аргумента, что является приятным синтаксическим сахаром.
Разрушение блоков
В настоящее время блоки ломаются, но вы можете добавить более интересное поведение блокам после того, как они столкнутся с мячом.
Откройте Crates.cs. Вы увидите код для OnCollisionEnter2D()
.
В OnCollisionEnter2D()
вы найдете только ссылку на функцию, которая увеличивает счет, когда игрок разбивает ящики. Но вы сразу же добавите больше.
Вращение объектов с помощью LeanTween
К настоящему времени вам может быть интересно, какие числа вы могли бы интерполировать дальше. На этом этапе вы будете использовать анимацию вращения для создания анимации уничтожения блоков.
В исходном коде, когда мяч сталкивается с блоками, то они просто исчезают. Теперь вы будете использовать LeanTween, чтобы добавить кирпичикам более интересный эффект.
Замените весь метод OnCollisionEnter2D()
на:
private void OnCollisionEnter2D(Collision2D collision)
{
//1
gameObject.GetComponent<Collider2D>().enabled = false;
//2
LeanTween.alpha(gameObject, 0.2f, 0.6f);
//3
LeanTween.rotateAround(gameObject, collision.GetContact(0).normal, 250.0f, 0.6f).setDestroyOnComplete(true);
// Increases the score
GameManager.Instance.IncreaseScore(1);
}
Вот что делает код:
- Изначально вы отключаете коллайдер игрового объекта, чтобы избежать дополнительных столкновений между моментом удара по блоку и его исчезновением со сцены.
- Чтобы создать иллюзию исчезновения блока, вы используете альфа-канал для уменьшения непрозрачности элемента до 0,2 за 0,6 секунды.
rotateAround()
поворачивает игровой объект вокруг точки, где произошло столкновение, на 250 градусов за 0,6 секунды. Это создает более отзывчивое ощущение, поскольку кирпичик вращается вокруг точки контакта между собой и мячом. Затем код указывает LeanTween удалить игровой объект после завершения анимации, а также элементы из сцены сразу после завершения отмеченных операций.
Теперь нажмите на Play и посмотрите, как круто выглядит ваша работа.
Анимация элементов пользовательского интерфейса
Вы прошли долгий путь, добавив анимацию в проект. Несмотря на то, что отдельные анимации просты, когда все вместе, композиция получается потрясающей.
Но если вы присмотритесь, то заметите, что не все имеет динамическое поведение.
Текст счета по-прежнему статичен. Он считает очки правильно, но в этом нет ничего особенного.
В Unity элементы пользовательского интерфейса также являются игровыми объектами, поэтому добавить некоторые эффекты должно быть просто, верно? Правильно!
Анимация увеличения счета
GameManager имеет ссылку на текстовый объект и отвечает за обновление счета.
В GameManager.cs найдите и замените весь код метода IncreaseScore(int value)
на этот:
public void IncreaseScore(int value)
{
gameScore += value;
scoreDisplay.text = gameScore.ToString();
// 1
LeanTween.cancel(scoreDisplay.gameObject);
scoreDisplay.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
scoreDisplay.transform.localScale = Vector3.one;
// 2
LeanTween.rotateZ(scoreDisplay.gameObject, 15.0f, 0.5f).setEasePunch();
LeanTween.scaleX(scoreDisplay.gameObject, 1.5f, 0.5f).setEasePunch();
}
Поскольку в этом коде появилось несколько новых функций, проанализируйте его по блокам:
- Этот блок сбрасывает внешний вид игрового объекта отображения счета. Эти строки останавливают любую операцию твининга, воздействующую на
scoreDisplay
, и сбрасывают его вращение и масштаб, чтобы избежать распространения ошибок во время игры. - Функции в этом блоке добавляют эффекты вращения и масштабирования к игровому объекту
scoreDisplay
. Здесь вы объявляете вращение по оси Z и масштабирование по оси X с той же функцией плавности.
Как вы, возможно, поняли, вы можете выполнять те же операции, что и для любого другого игрового объекта, над элементами пользовательского интерфейса. Однако в то время как код анимации был инкапсулирован внутри каждого из них, код анимации для счета находится внутри класса GameManager
.
Теперь запустите игру и посмотрите, как прибавляется анимированный игровой счет.
Вы можете использовать LeanTween для анимации других элементов, а не только тех, в которые включили файлы скриптов.
Анимация цвета фона
Если вы нажмете на Play, то увидите, что игра сделана, но еще есть возможности для улучшения. Фон может реагировать и на игровые действия. Это прекрасная возможность добавить еще несколько интересных визуальных эффектов.
Прежде чем перейти к коду, разверните игровой объект Level Geometry в окне Hierarchy. Затем выберите игровой объект Background и просмотрите его свойства в окне инспектора.
Обратите внимание, что цвет компонента Sprite Renderer отличается от белого. Это помогает создать иллюзию трехмерного пространства, при этом задний план находится на расстоянии от переднего плана.
Чтобы действовать, вам понадобится ссылка на фоновый игровой объект. Итак, вверху GameManager.cs, прямо внизу строки:
public GameObject Paddle;
Добавьте еще две переменные, чтобы указать ссылку на фоновый игровой объект и то, как сильно он должен трястись, например:
public GameObject Background;
public float backgroundShakeRate = 2.0f;
Теперь снова замените код метода IncreaseScore(int value)
на следующее:
public void IncreaseScore(int value)
{
gameScore += value;
scoreDisplay.text = gameScore.ToString();
LeanTween.cancel(scoreDisplay.gameObject);
scoreDisplay.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
scoreDisplay.transform.localScale = Vector3.one;
LeanTween.rotateZ(scoreDisplay.gameObject, 15.0f, 0.5f).setEasePunch();
LeanTween.scaleX(scoreDisplay.gameObject, 1.5f, 0.5f).setEasePunch();
// 1
LeanTween.move(Background.gameObject, Random.insideUnitCircle * backgroundShakeRate, 0.5f).setEasePunch();
// 2
Background.LeanColor(Color.red, 0.3f).setEasePunch().setOnComplete(() =>
{
Background.GetComponent<SpriteRenderer>().color = new Color(0.38f, 0.38f, 0.38f);
});
}
И move
, и LeanColor
уже использовались для других элементов. Теперь вы будете использовать их немного по-другому:
- Этот код использует
LeanTween.move()
. Но в этом случае движение выполняется в случайном направлении с помощьюRandom.insideUnitCircle
для возврата случайногоVector2
внутри единичного круга (круг с радиусом 1). - Этот код показывает, как определить лямбда-выражение, которое будет выполняться сразу после завершения анимации. В этом случае код переопределяет атрибут цвета фонового спрайта на значение по умолчанию, чтобы избежать изменения цвета, точно так же, как размер мяча сбрасывается в каждом раунде анимации.
Не забудьте добавить ссылку, которую вы создали в скрипте, в редакторе! Перетащите игровой объект Background из окна иерархии в соответствующий слот в GameManager.
Теперь нажмите на Play и наслаждайтесь игрой. Посмотрите, насколько лучше игра выглядит по сравнению с первоначальным проектом:
Куда двигаться дальше
Отсюда вы можете увести что угодно!
Вы можете скачать готовые файлы проекта, нажав кнопку «Скачать материалы урока» вверху страницы, и продолжить изучение.
Почему бы не попробовать создать собственные кривые замедления в редакторе Unity? Попробуйте заменить некоторые функции плавности для элементов в проекте и модифицировать их по своему усмотрению.
Вы также можете просмотреть официальную документацию LeanTween для получения дополнительной информации об API.
Надеюсь, вам понравился этот урок. Если у вас есть вопросы, комментарии или вы хотите показать свой законченный проект, присоединяйтесь к форумам ниже!
Автор перевода: Jean Winters
Источник: Tweening Animations in Unity with LeanTween
Смотрите также:
Введение в Unity: приступая к работе