Сайт о телевидении

Сайт о телевидении

» » Как сделать 2d анимацию в unity3d. Информационный портал по безопасности

Как сделать 2d анимацию в unity3d. Информационный портал по безопасности

Где взять дельные уроки о создание 2D игр на движке unity(любая версия)?

Геймплей в 2D

Несмотря на то что Unity известен своими 3D возможностями, он может быть использован и для создания 2D игр. Знакомые функции редактора также доступны, но с полезными для 2D разработки дополнениями.

Самая заметная черта — это кнопка переключения режима 2D на тулбаре окна Scene. Когда этот режим активен, будет установлен ортографический вид (камера смотрит вдоль оси Z и оси Y, направленной вверх). Это позволит вам легко визуализировать сцену и размещать 2D объекты.

For a full list of 2D components, how to switch between 2D and 3D mode, and the different 2D and 3D Mode settings, see 2D or 3D Projects.

2D Графика

2D объекты называются Спрайтами. По сути, спрайты представляют собой стандартные текстуры, но для более эффективного объединения и управления спрайтами в процессе разработки, есть специальные техники. Unity предоставляет встроенный Редактор Спрайтов, позволяющий извлечь спрайт из большого изображения. Он позволяет редактировать компоненты изображений внутри единой текстуры. Вам следует его использовать, например, для разделения рук, ног и тела персонажа внутри одного изображения.

Рендер спрайтов осуществляет компонент Sprite Renderer (аналог Mesh Renderer для 3D объектов). Вы можете добавить его через (, либо создать спрайт с уже прикрепленным к нему компонентом через меню:).

In addition, you can use a Sprite Creator tool to make placeholder 2D images.

2D Физика

Unity имеет отдельный движок для 2D физики, что делает оптимизацию доступной только для 2D объектов. Его компоненты соответствуют стандартным компонентам 3D физики, таким как Rigidbody, Box Collider и Hinge Joint, но с добавлением к имени “2D”. Так, спрайтам могут быть добавлены компоненты Rigidbody 2D, Box Collider 2D и Hinge Joint 2D. Большинство 2D компонентов представляют собой просто “сплющенные” версии соответствующих 3D компонентов (например, Box Collider 2D — квадрат, а Box Collider — куб), однако и здесь есть несколько исключений.

Смотрите раздел руководства Физика для получения дополнительной информации о концепциях и компонентах 2D физики.

Подготовка своего персонажа

Существует три главных шага по созданию “с нуля” своего анимированного гуманоидного персонажа: моделирование , риггинг и скиннинг .

Моделирование

Это процесс создания своих гуманоидных мешей в одном из инструментов 3D моделирования — 3DSMax, Maya, Blender, и т.д. Хоть это и целая тема для обсуждения сама по себе, существует несколько принципов, которые рекомендуется соблюдать, чтобы ваша модель была совместима с анимацией в Unity проекте.

  • Соблюдайте разумную топологию . Понятие “разумной” структуры вашего меша довольно тонкое, но в целом вам следуем помнить о том, как вершины и треугольники модели будут искажаться при анимации. Неправильная топология приведёт к неприятным искажениям меша при движениях модели.

    Изучая существующие 3D меши персонажей, можно узнать много нового о том, как правильно размещать топологию и почему.

  • Не забывайте про масштаб вашего меша. Попробуйте импортировать модель и сопоставить её размер с “метрическим кубом” (длина одной стороны стандартного Unity примитива “куб” равна одной условной единице, так что такой примитив можно рассматривать как однометровый куб в большинстве случаев). Проверьте единицы измерения вашего приложения для 3D моделирования и скорректируйте настройки экспорта так, чтобы размер модели был в нужных вам пропорциях к метровому кубу. Если не учитывать это при работе над моделями, легко прийти к ситуации, когда вы создадите несколько разных моделей без учёта масштаба и они окажутся несоразмерны после импорта в Unity.
  • Располагайте меш так, чтобы ступня персонажа находилась в центре вращения модели. Так как обычно персонаж ходит по горизонтальной поверхности, будет намного проще с ним работать, если его центр вращения(то есть, его позиция трансформации) будет на этой поверхности.
  • По возможности, моделируйте в Т-позе . Это даст дополнительное пространство для манёвра при работе над труднодоступными местами (например, подмышками). Кроме того, это упростит размещение рига внутри меша.
  • Держите модель в порядке . Не оставляйте дырок в поверхности, объединяйте вершины и избавляйтесь от скрытых поверхностей, которые никогда не будут видны.

    Геймплей в 2D

    Это поможет при скиннинге, особенно если скиннинг автоматизирован.

Риггинг

Это процесс создания скелета из сочленений для управления движениями вашей модели.

Программы для 3D моделирования предоставляют множество инструментов создания сочленений гуманоидного рига.

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

Чтобы риг работал с Mecanim, таз должен быть корневым элементом всей иерархии костей и в скелете должно быть не менее 15 костей.

Иерархия сочленение/кость должна соответствовать натуральной структуре создаваемого персонажа. Поэтому руки и ноги должны идти в парах и вам следует соответствующе их называть (напр. “arm_L” для левой руки, “arm_R” для правой и т.д.). Возможные структуры иерархии:-

  • Таз — позвоночник — грудная клетка — плечи — рука — предплечье — кисть
  • Таз — позвоночник — грудная клетка — шея — голова
  • Таз — бедро — нога — ступня — палец — конец_пальца

Скиннинг

Это процесс привязки меша к скелету.

Скиннинг включает в себя связывание вершин в вашем меше с костями скелета. Вершина может быть связана с костью напрямую (жёсткая привязка) или с несколькими костями, используя на них смешанные воздействия (мягкая привязка). В разных программах используются разные способы, например, привязывание отдельных вершин и вписывание в меш степени воздействия на каждую кость. Изначальная настройка обычно автоматизирована, к примеру, с помощью поиска ближайшего воздействия, или с помощью “heatmap”. Обычно скиннинг требует изрядного количества работы и тестирования с помощью анимаций, чтобы достичь желаемых результатов деформации скина. Вот несколько основных рекомендаций для этого процесса:

  • Используйте автоматизацию для начальной настройки скиннинга (см. соответствующие руководства для 3DMax, Maya и т.д.).
  • Создавайте простые анимации или импортируйте готовые анимации для своего рига, чтобы проверить скиннинг. Это позволит вам быстро выяснить, хорошо ли выглядит ваш скиннинг во время движения.
  • Постепенно редактируйте и улучшайте свою работу по скиннингу.
  • Используйте не более 4 воздействий при использовании мягкой привязки, т.к. это наибольшее количество, которое может использовать Untiy. Если к части меша будет применено более четырёх воздействий, то как минимум часть информации будет потеряна при проигрывании анимации в Unity.

Использование Гуманоидных Персонажей



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

1. Установка

Итак, работа начинается с покупки и установки самого плагина с Asset Store:



Далее добавляем плагин в рабочую область: Window >> Puppet2D

2.Создание скелета. Подготовка

Перед созданием скелета, выстраиваем спрайты на сцене и создаем Layer для персонажа (куда поместим спрайты, я назвала его «Player»):

И Sorting Layer для костей и контроллеров (тут «Bones» и «Controllers»). Попутно выставляем слоя для костей и контроллеров в самом Puppet:

3.Создание скелета

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

Создание начинается с кнопки «Create Bone Tool» (1)

Нажимаем ЛКМ на нужных местах, по окончании - ПКМ или «Finish Bone» (2). Если сначала нажмем на уже существующую кость и создадим от нее еще одну, то та станет костью-родителем.

Для хребтов людей и животных существует кнопка «Create Spline Tool»(3). Помечаем начальную и конечную точку, а показатель (4) - количество костей между данными точками. На концах этих точек автоматически появятся контроллеры. Завершаем сплайн кнопкой «Finish Spline»(5).

В итоге должен получится примерно такой скелет:

4.Создание скелета. Вешаем контроллы

Далее все просто - на конечности вешаем контроллы:

(1) - Контроллер для конечностей (рук, ног)
(2) - Контроллер-родитель
(3) - Контроллер только для поворотов (например, головы)

5.Создание скелета. Привязка спрайтов к скелету

Существует 2 способа привязки:

  • если одному спрайту соответствует одна кость;
  • если одному спрайту соответствуют 2 и больше костей.
В первом случае все очень просто: выбираем нужные кости, выбираем нужный спрайт и жмем кнопку «Parent Object To Bones»:

Во втором придется немного заморочится, ибо нужно конвертнуть спрайт в мэш. Выбираем спрайт и жмем кнопку «Convert Sprite To Mesh»:

Показатель «Type of Mesh»(1) (От 0 до 4) указывает на количество треугольников в полигоне. Чем выше тип, тем их больше.

Следующим шагом будет привязка этого мэша к костям. Выбираем его, выбираем кости и жмем «Bind Smoth Skin»:

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

6. Создание скелета. Корректировка весов

Если объяснить упрощенно, то веса показывают, какая кость гнет какой мэш. Выбираем нужный мэш, затем редактируем, начиная с кнопки «Paint Weights»:

Выбираем нужную кость и там где белый цвет - кость гнет мэш, там где черный - нет:

Выбираем толщину и жесткость кисти и закрашиваем веса с помощью ЛКМ:

Shift + ЛКМ = Смяхчение переломов
Ctrl+ ЛКМ = Стирание весов

Заканчиваем редактирование кнопкой «Finish Edit Skin Weights».

7. Анимация

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

Напоследок добавлю туториал с оффициального YouTube-канала Puppet2D:

Вы можете помочь и перевести немного средств на развитие сайта

Пролог.
И снова здравствуйте. Это второй урок по созданию RPG на Unity3D. Изначально я хотел написать его не много по другому но планы у меня изменились и пришлось все предумывать. Сначала задумывалось делать 2 камеры с видо от первого лица и от 3, но в итоге я оставил только от третьего. Сегодня я все скрипты покажу вам полностью сразу и постораюсь объяснить малопонятные вещи в коде дабы экономить свое время и ваше.
В прошлом уроке я забыл написать о «build», то есть непосредственно компиляции проекта.По этому мы сделаем это сейчас. Откроем наш проект. Если открылась пустая сцена нажмем «Ctrl+o» и откроем сцену которую мы делали на прошлом уроке. Нажмем «Ctrl+Shift+b» и в открывшемся окне нажмем «Add Current». Это поставит наше меню в список компилирования и даст ему порядковый номер. При открытии компилированного проекта первой открывается сцена под номером 0. Если нажмем «Build And Run» наш проект скомпилируется и запустится.

План урока.
1) Импорт персонажа.
2) Передвижение персонажа.
3) Настройка камеры
4) Анимация персонажа.
Импорт персонажа.
Сцена.
Создаем «Terrain» с размерами 200х200. Вешаем какую-нибудь текстуру для удобства отображения. Создадим источник света.
Персонаж
Возьмем заранее подготовленного персонажа с анимациями, я взял из «Asset Store»(«Window>>Asset Store» или Ctrl+9) персонажа с названием Blade Girl NPC. Эта моделька стоит 15$ Она у меня уже есть и я буду использовать именно её. Вы можете там же поискать бесплатные(Среди них есть достойные). или же просто в интернете поискать какие нибудь. В эту модель уже впихнута анимация различных действий, атака, бег и тд. и тп. и даже танец Гангнам Стайл))).


После импорта находим находим в окне «Project» префаб персонажа, у меня он называется «Balde_girl_Prefab» и находится в папке «Blade_girl». Перетаскиваем этот префаб на сцену, и видим наш персонаж, только каойто он большой через чур, это не беда. В инспекторе в пункте «Scale» выставим все по единичке, и все хорошо становиться, моделька стала нормальных размеров, можно работать дальше

«Префаб - это один из типов ресурсов, предназначений для многократного использования и хранящийся в Project View. Префаб может быть вставлен в любое количество сцен и многократно в одну сцену. Когда префаб добавляется в сцену, создаётся его экземпляр. Все экземпляры являются ссылками на оригинальный префаб и фактически его клонами. Независимо от того, как много экземпляров в проекте, при изменении префаба изменяются соответственно и все его экземпляры.»

Нажимаем «Add component>>Physics>>Rigidbody» и «Add component>>Physics>>Capsule Collider». В «Capsule Collider» Выставляем размеры нашей капсулы что бы получилось как на картинке, слегка чуть больше модельки самой.


В «Rigidbody» ставим галочку «Use gravity». Раскрываем вкладку «Constraints» и ставим все 3 галочки на «Freeze Rotation». Это нужно для того что бы наш персонаж не проваливался сквозь землю, не падал на землю если вдруг окажется на неровности и тому подобное.
Программируем персонажа на перемещение.
Создадим c# скрипт «movePlayer».

200?"200px":""+(this.scrollHeight+5)+"px");">using UnityEngine;
using System.Collections;

Public class movePlayer: MonoBehaviour {

Private GameObject player; //Переменна объекта персонажа с которым будем работать.

Public static int speed = 6; //Скорость перемещения персонажа. Запись public static обозначает что мы сможем обращаться к этой переменной из любого скрипта
public static int _speed; //постоянная скорость перемещения персонажа
public int rotation = 250; //Скорость пповорота персонажа
public int jump = 3; //Высота прыжка

Public static bool IsDrawWeapon; //Двоичная переменная, которая будет отвечать достануто ли у нас оружие.
public static float x = 0.0f; //угол поворота персонажа по оси x
void Start () {
IsDrawWeapon = false; //По умолчанию оружие у нас спрятано.
_speed = speed; //Задаем постоянное стандартное значение скорости персонажа
player = (GameObject)this.gameObject; //Задаем что наш персонаж это объект на котором расположен скрипт
}

Void Update () {
if(IsDrawWeapon == true) //Если оружие вытащено
{
speed = _speed * 2; // Меняем скорость передвижени(я это сделал потому что, у этой моделки нету анимаций движения простым шагом с мечом. а понижать скорость анимации у бега получиться не красиво)
{
player.transform.position += player.transform.forward * speed * Time.deltaTime; //Перемещаем персонажа в перед, с заданой скорость. Time.deltaTime ставится для плавного перемещения персонажа, если этого не будет он будет двигаться рывками
}
if(Input.GetKey(KeyCode.S))
{
speed = _speed / 2; //При передвижениии назад снижаем скорость перемещения
}
{
speed = _speed * 2; //Возвращаем cтандартное значение
}
{
}
{
}
{
}

If(Input.GetKey (KeyCode.Tab)) //При нажатии и на кнопку Tab
{
IsDrawWeapon = false; //Мы спрячем наше оружие.
}
}
else if(IsDrawWeapon == false) //Если оружие не спрятано. |||||| Сделано разделение на движения в зависимости от того вытащено ли у нас оружие или нет, потому что персонаж будет перемещаться сразной скорость у меня в этих случаях, как я уже написал из за отсутсвия некоторых анимаций у модельки.
{
speed = _speed;//Скорость в стандартное значение
if(Input.GetKey (KeyCode.LeftShift)) //Если зажать левый Shift
{
speed = _speed * 2; //Увеличиваем скорость перемещения(бег)
}
if(Input.GetKeyUp (KeyCode.LeftShift)) //Если отпустить
{
speed = _speed; //Возвращаем стандартное значение
}
if(Input.GetKey(KeyCode.W)) //Если нажать W
{
player.transform.position += player.transform.forward * speed * Time.deltaTime; //Перемещаем персонажа в перед.
}
if(Input.GetKey(KeyCode.S))
{
speed = _speed / 2;
player.transform.position -= player.transform.forward * speed * Time.deltaTime; //Перемещаем назад
}
if(Input.GetKeyUp (KeyCode.S))
{
speed = _speed; //Возвращаем cтандартное значение
}
if(Input.GetKey (KeyCode.A))
{
player.transform.position -= player.transform.right * speed * Time.deltaTime; //перемещаем в лево
}
if(Input.GetKey (KeyCode.D))
{
player.transform.position += player.transform.right * speed * Time.deltaTime; //перемещаем в право
}
if(Input.GetKey (KeyCode.Space))
{
player.transform.position += player.transform.up * jump * Time.deltaTime; //Прыгаем
}
if(Input.GetKey (KeyCode.Tab)) //при нажатии на кнопку таб
{
IsDrawWeapon = true; //Мы вытащим наше оружие
}
}

//Поворачиваем персонажа. Так как наша переменная x глобальна, из скрипта камеры в неё будем записывать длину на сколько сместился указатель мыши и по оси X и относительно этого будет повернут наш персонаж
Quaternion rotate = Quaternion.Euler (0,x,0); //Создаем новую переменную типа Quaternion для задавания угла поворота
player.transform.rotation = rotate; //Поворачиваем персонаж


Скрипт помещаем на персонажа.
Управление камерой.
Создадим еще один c# скрипт, и назовем его «moveCam»

200?"200px":""+(this.scrollHeight+5)+"px");">codeusing UnityEngine;
using System.Collections;

Public class CamMove: MonoBehaviour {
public Transform target; //Объект за которым летаем(Наш персонаж)
public float distance = 3.0f; //На каком ратоянии от него
public float xSpeed = 125.0f; //Чуствительность по Х
public float ySpeed = 50.0f; //Y Чуствительность
public float targetHeight = 2.0f; //Высота относительно объекта
//Минимальный и максимальный угол поворота Y инче камеру разверет, Дальше у нас будет простая функция для инвертации их в обратные числа
public float yMinLimit = -40;
public float yMaxLimit = 80;
//Максимальное удаление и приближение камеры к персонажу, искорость.
public float maxDistance = 10.0f;
public float minDistance = 0.5f;
public float zoomRote = 90.0f;

Private float x = 0.0f; //Угол поворота по Y?
private float y = 0.0f; //Уго поворота по X?

//Добавляем в меню

Public void Start() {
//переворачивам углы
Vector3 angles = transform.eulerAngles;
x = angles.y;
y = angles.x;

If(rigidbody)
rigidbody.freezeRotation = true; //Если камера столкнется с физ.объектомона остановиться
}

Public void LateUpdate() {
if (target) {//Если цель установлена(Персонаж)
//Меняем углы согласно положению мыши
x += Input.GetAxis("Mouse X") * xSpeed * 0.02f;
y -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f;
//Меняем дистанция до персонажа.
distance -= (Input.GetAxis ("Mouse ScrollWheel") * Time.deltaTime) * zoomRote * Mathf.Abs(distance);
distance = Mathf.Clamp (distance, minDistance, maxDistance);

Y = ClampAngle(y,yMinLimit, yMaxLimit); //Вызыв самописной функции для ограничения углов поврот
movePlayer.x = x;
//Повернуть камеру согласно поченым данным
Quaternion rotation = Quaternion.Euler(y, x, 0);
transform.rotation = rotation;

//Двигаем камеру и следим за персонажем
Vector3 position = rotation * new Vector3(0.0f, targetHeight+0.5f, -distance) + target.position;

//Следуйщи код нужен что бы камера не проваливалась по ланшафт
RaycastHit hit;
Vector3 trueTargetPosition = target.transform.position - new Vector3(0, -targetHeight,0);
if(Physics.Linecast (trueTargetPosition, transform.position, out hit))
{
float tempDistance = Vector3.Distance (trueTargetPosition, hit.point) - 0.28f;
position = target.position - (rotation * Vector3.forward * tempDistance + new Vector3(0, -targetHeight, 0));
transform.position = position;
}
}

}
//Меняем значения углов
public static float ClampAngle (float angle, float min, float max) {
if(angle < -360)
angle += 360;
if(angle > 360)
angle -= 360;
return Mathf.Clamp (angle, min, max);
}
}


Скрипт кидаем на камеру. Камера должна быть перемещена в префаб персонажа в окне «Hierarchy». А в компоненте скрипта на камере в поле «Target» долже быть помещен наш префаб из окна «Hierarchy».
Анимация
Создадим новый скрипт и назовем его «AnimatePlayer»

200?"200px":""+(this.scrollHeight+5)+"px");">using UnityEngine;
using System.Collections;

Public class AnimatePlayer: MonoBehaviour {

Public void Start ()
{
// Устанавливаем все клипы анимации в режим цикла
animation.wrapMode = WrapMode.Loop;
// Кроме следующих
animation["Attack01"].wrapMode = WrapMode.Once;
animation["jump"].wrapMode = WrapMode.Once;
animation["Skill"].wrapMode = WrapMode.Once;
//У них одиночное выполнение

//Останавливаем выполнение анимаций.
animation.Stop();
}

Public void Update () {
// На основе нажатой клавиши выполняем анимацию
if(movePlayer.IsDrawWeapon == false) //Если оружие не вытащено
{
if (Input.GetAxis("Vertical") > 0.0f) //Проверяем на изминениея позиции персонажа повертикали, если да
{
//Проверяем скорость Передвижения персонажа,
{
animation.CrossFade ("Run00"); //Если зажата клавиша shift, значит грузим анимацию бега
}
else
{
animation.CrossFade("Walk"); //В противном случаее ходьбу
}
}
< 0.0f) //Далее все по анологии
{
if(movePlayer.speed == movePlayer._speed * 2)
{
animation.CrossFade ("B_Run00"); //бег назад
}
else
{
animation.CrossFade ("B_Walk"); //ходьба назад
}
}
else if (Input.GetAxis("Horizontal") > 0.0f)
{
if(movePlayer.speed == movePlayer._speed * 2)
{
animation.CrossFade ("R_Run00"); //бег в право
}
else
{
animation.CrossFade ("R_Walk"); //Шагание в право
}

}
< 0.0f)
{
if(movePlayer.speed == movePlayer._speed * 2)
{
animation.CrossFade ("L_Run00"); //лево
}
else
{
animation.CrossFade ("L_Walk"); //лево
}
}
else if(Input.GetKey (KeyCode.Space)) //если сделан прыжок
{

Animation.Play ("Jump_NoBlade"); //Включаем анимацию прыжка
}
else
{
animation.CrossFade("Idle"); //просто стоим
}
}
else if(movePlayer.IsDrawWeapon == true) //если оружие вытащено
{
if (Input.GetAxis("Vertical") > 0.0f)
{
animation.CrossFade ("Run"); //бег в перед
}
else if(Input.GetAxis("Vertical") < 0.0f)
{
animation.CrossFade ("B_Run"); //назад
}
else if (Input.GetAxis("Horizontal") > 0.0f)
{
animation.CrossFade ("R_Run"); //в право
}
else if(Input.GetAxis("Horizontal") < 0.0f)
{
animation.CrossFade ("L_Run"); //в лево
}
else if(Input.GetKey (KeyCode.Space))
{
animation.Play ("jump"); //Прыжок
}
else
{
animation.CrossFade("AttackStandy"); //просто стоим
}

//Анимация атаки
if (Input.GetMouseButton (0)) //Если нажать маус 1
animation.CrossFade("Attack01"); //Включаем анимацию атаки
if (Input.GetMouseButton (1)) //Если нажать маус 2
animation.CrossFade("Skill"); //Включаем анимацию скила
}
}
}


Скрипт должен быть помещен на персонажа. В окне «Project» создадим папку «Prefab» и перетащим в нее префаб персонажа из окна «Hierarchy» что бы сохранить все на будущее и не повторять все заново.
На сегодня все всем надеюсь моя статья вам будет полезна.


Часть 2: бегущий персонаж

Каждому здравствуй. Продолжаем дело, начатое в первой части. Теперь у нас есть платформа и стоящий на ней персонаж с анимацией покоя. Настало время обучить нашего персонажа бегать вправо-налево по платформе.

Загрузим сцену из первой части. Напомню, что в прошлый раз мы импортировали несколько спрайтов в папкуAssets - Sprites . На каждый случай, внизу поста еще раз приведу ссылку на спрайты. Среди них должен быть спрайт под наименованием Run . Мы будем применять его для создания анимации бега. Для этого нам нужно проделать те же действия по перевоплощению одиночного спрайта в коллекцию, как и при создании анимации покоя. Лаконично напомню: выделяем спрайт, в окне Inspector устанавливаем качество Sprite Mode какMultiple , нажимаем ниже Sprite Editor , нарезаем изображение в режиме Grid либо Automatic .

Сейчас в окне Hierarchy выбираем Character и переходим в окно Animation . Нажимаем на поле с анимацией Idle и выбираем Create New Clip , Дабы сделать анимацию бега. Сбережем файл анимации в папке Assets -Animations под именем Run .

Новая сделанная анимация Run стала нынешней в окне Animation . Разворачиваем спрайт Run в окне Project , выделяем все фалы Run_0… Run_9 и перетаскиваем в окно Animation . Установим пока значение Sample равное 24.

Все это мы теснее делали в первой части, а сейчас будет что-то новое. Перейдем в окно Animator . Теперь там отображены три анимации: Any State , Idle и Run . Нам предстоит задать данные перехода из анимации Idle в анимацию Run , то есть из состояния покоя в состояние бега. В нижнем левом углу есть поле Parameters . Нажимаем на плюсик, выбираем Float и называем новейший параметр как Speed . Тем самым мы сотворили параметр типа число с плавающей запятой, обозначающий скорость перемещения персонажа. Именно в зависимости от значения этого параметра будет протекать переключение из анимации покоя в анимацию бега. Сейчас нажимаем правой кнопкой мыши на анимацию Idle , выбираем Make Transition и нажимаем левой кнопкой мыши на анимацию Run . Между анимациями появится линия со стрелкой. Передвиньте мышкой прямоугольники анимации, если нехорошо видно. Кликнем по линии со стрелкой. В окне Inspector отобразятся свойства перехода между анимациями. Обратим внимание на низ окна, в раздел Conditions . Кликнем на параметр Exit Time и поменяем его на Speed . Второе поле Greater оставим без изменений, а в третьем введем значение 0.01 . Мы сделали условие перехода из анимации покоя в анимацию бега - оно происходит, когда значение параметра скорости становится немногим огромнее нуля.

Сейчас необходимо сделать обратный переход - из Run в Idle . Делаем все с точностью напротив: Make Transition от Run к Idle , выделяем переход, в Conditions устанавливаем Speed - Less - 0.01 .

Сейчас у нас есть две анимации и данные перехода между ними. Но пока ничего трудиться не будет, потому что все что мы сделали необходимо «оживить» при помощи скрипта. Давайте перейдем в окно Project и сотворим в папке Assets подпапку Scripts . Добавим в нее новейший C# Script , назовем егоCharacterControllerScript и откроем на редактирование.

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

Using UnityEngine; using System.Collections; public class CharacterControllerScript: MonoBehaviour { //переменная для установки макс. скорости персонажа public float maxSpeed = 10f; //переменная для определения направления персонажа вправо/влево private bool isFacingRight = true; //ссылка на компонент анимаций private Animator anim; ///

/// Исходная инициализация /// private void Start() { anim = GetComponent(); } /// /// Исполняем действия в способе FixedUpdate, т. к. в компоненте Animator персонажа /// выставлено значение Animate Physics = true и анимация синхронизируется с расчетами физики /// private void FixedUpdate() { //используем Input.GetAxis для оси Х. способ возвращает значение оси в пределах от -1 до 1. //при стандартных настройках плана //-1 возвращается при нажатии на клавиатуре стрелки налево (либо клавиши А), //1 возвращается при нажатии на клавиатуре стрелки вправо (либо клавиши D) float move = Input.GetAxis("Horizontal"); //в компоненте анимаций изменяем значение параметра Speed на значение оси Х. //приэтом нам необходим модуль значения anim.SetFloat("Speed", Mathf.Abs(move)); //обращаемся к компоненту персонажа RigidBody2D. задаем ему скорость по оси Х, //равную значению оси Х умноженное на значение макс. скорости rigidbody2D.velocity = new Vector2(move * maxSpeed, rigidbody2D.velocity.y); //если нажали клавишу для перемещения вправо, а персонаж направлен налево if(move > 0 && !isFacingRight) //отражаем персонажа вправо Flip(); //обратная обстановка. отражаем персонажа налево else if (move < 0 && isFacingRight) Flip(); } /// /// Способ для смены направления движения персонажа и его зеркального отражения /// private void Flip() { //меняем направление движения персонажа isFacingRight = !isFacingRight; //получаем размеры персонажа Vector3 theScale = transform.localScale; //зеркально отражаем персонажа по оси Х theScale.x *= -1; //задаем новейший размер персонажа, равный ветхому, но зеркально отраженный transform.localScale = theScale; } }

Выходит, мы завели несколько переменных: для задания максимальной скорости перемещения, для определения направления (вправо/влево) и для работы с компонентом Animator . Примерно все действия происходят в способе FixedUpdate . В нем мы получаем значение оси Х , которое меняется при нажатии на клавиатуре клавиш налево-вправо либо A-D (если не меняли соответствующие настройки плана!). После этого устанавливаем это значение параметру Speed компонента Animator . Обратите внимание, что мы берем модуль этого значения при помощи способа Mathf.Abs , так как при создании условий перехода между анимациями покоя и бега мы сопоставляем значение параметра с позитивным числом 0.01 . Нам тут не значимо, в какую сторону бежит персонаж. Значимо лишь величина значения. Дальше задаем скорость перемещения по оси Х в соответствии со значением максимальной скорости. И, наконец, проверяем, в какую сторону бежит персонаж, и в какую сторону он в данный момент повернут. Если он бежит вправо, а повернут налево - разворачиваем его вправо путем инвертирования его размера по оси Х . И напротив. Этим нехитрым методом мы избавились от необходимости делать две анимации взамен одной: для бега вправо и для бега налево.

Сберегаем скрипт. В Unity перетаскиваем его на нашего Character в окне Hierarchy . Запускаем игру, нажимаем налево-вправо либо A-D.

Капитан Коготь сейчас может бегать! Скорость анимации получилась быстроватой. Ее дозволено снизить путем уменьшения значения Sample в окне Animation для анимации Run (значение 12 будет типично). Если единовременно с игрой у вас видно окно Animator , то вы ув

В этой статье поговорим о 2D анимациях в Unity. Я расскажу о своем опыте работы с родными анимациями в юнити, о том, насколько тайм-лайны похожи на флэшевские, об управлении анимациями, event"ах, вложенности, и о том, как художник справляется с анимированием.

Для начала, немного теории.

В Unity есть две сущности:

1. Анимация (то, что отображается в окно «Animation»)
2. Mechanim дерево анимаций (то, что отображается в окне «Animator»).


Ниже я немного расскажу, что это такое и как нам может приходиться (или не пригодиться).

Animation

Итак, анимация. По сути - это таймлайн с ключевыми кадрами. Здесь вы можете двигать, поворачивать, масштабировать ваши объекты. Естественно, можно рисовать кривые и пользоваться разными изингами. И даже управлять любыми (в т.ч. самописными) их свойствами. То есть вполне можно написать компонент с float паблик-значением «яркость» и эту самую «яркость» анимировать наравне с x, y, z штатными средствами. Спрайты поддерживают покадровую анимацию.


Кстати, несмотря на то, что у каждой анимации есть FPS (поле «sample»), сами анимации к FPS не привязаны. Они привязаны ко времени. Т.е. если вы делаете анимацию с 5 FPS, где у вас объект двигается из точки А в точку Б с помощью задания двух ключевых кадров в начале и в конце, то в игре этот объект не будет двигаться ступеньками с 5 FPS. Анимация рассчитывается каждый кадр игры, а FPS внутри анимации сделан лишь для вашего удобства, чтобы вам не частить кадры.

Animator

Это - большая и сложная система, которая непосредственно управляет анимациями. То есть анимация - это просто файл (ресурс) с настройками ключевых кадров и сама по себе ничего не умеет. Вот именно компонент «Animator» - это то, что умеет играть эти анимации.

Кроме того, вы можете создавать дерево этих анимаций с морфингом между ними. Т.е. если у вас есть персонаж, анимированный перекладками (когда каждая часть тела - отдельный спрайтик, который вы вращаете/двигаете), то вполне можно сделать анимацию ног отдельно, анимацию рук - отдельно. А потом (с помощью мышки) настроить условие, что от скорости движения вашего объекта, mechanim аниматор будет включать либо анимацю ног «ходьба», либо «бег». А стрелять ваш персонаж будет отдельной анимацией, которая никак не связана со скоростью переставления ног.

В самом же просто случае, ваш аниматор будет выглядеть так:


Начинаем шаманить.

Пока все понятно. Но давайте подумаем, как сделать что-то чуть более сложное?

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


1. сугроб, шевелясь, двигается влево
2. из сугроба выглядывает заяц (анимация пульсации останавливается):

3. сугроб двигается вправо

В принципе, ничего сложного. Анимируем пульсацию сугроба внутри объекта, внешним аниматором двигаем его влево, потом скрываем, вместо него показываем покадровую анимацию выглядывающего зайца, потом обратно. И все это на одном таймлайне (кроме «внутренней» анимации сугроба).

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

Хотелось бы большей гибкости.

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

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

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

То есть сделать так:


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

Что нам для этого понадобится? Unity позволяет добавлять на анимацию вызов кастомных юзер event"ов. Это именно то, что нам нужно! Осталось только правильно все написать.

Первое, что нам понадобится, это написать простой компонент (в нашем случае он называется GJAnim) и повесить его на тот же объект, на котором висит наш аниматор. Именно методы этого компонента мы сможем вызывать событиями с таймлайна.

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

Public void Pause() { _animator.speed = 0; } protected void Resume() { _animator.speed = 1; }

Где _animator - это переменная, в которой мы закешировали компонент " Animator ":

Animator = GetComponent();

Если вы обратили внимание на скрин выше, над ключевым кадром, который я пометил цифрой «2» стоит небольшая вертикальная черта. Именно за ней скрывается вызов события (метода) «Pause»:


Стоит отметить, что в такие события можно даже передавать параметр. Поддерживаются string, float и объект из библиотеки (не со сцены).

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

Public void ResumeParent() { Transform pr = transform; while (true) { pr = pr.parent; if (pr == null) { Debug.LogWarning("No GJAnim found in parents!"); return; } GJAnim a = pr.gameObject.GetComponent(); if (a != null) { a.Resume(); return; } } }

Этот метод ищет среди родителей компонент " GJAnim " и снимает его с паузы. Соответственно, ставим это событие на окончание анимации нашего кролика:


Profit!

Собственно, все. Мы написали простой компонент, который позволяет управлять вложенными/родительскими анимациями и обладает достаточной гибкостью. Возможно, понадобится еще метод типа ResumeByName(string) , который бы снимал с паузы конкретную анимацию, а не первую родительскую.

Кроме того, все делается в пределах юнитевского UI и достаточно прозрачно для любого аниматора. Наш художник через час попадания ему в руки этого инструмента, уже во всю анимировал.

О багах Unity и сумасшествии.

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

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

Так вот, мы заметили, что кадры иногда проскакивают.

Долго-долго дебажили, много писали в лог… и вот что выяснили:

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

Это влечет за собой чуть ли не полностью неисправимый фейл. Мы ловили ситуацию, когда аниматор выполнял все действия с кадром и вставал на паузу (это ок), а потом в этот же кадр выполнял еще и следующий кадр. То есть за один кадр рассчитывал сразу два кадра анимации. И то, что в 1-м кадре было событие, ставящее скорость анимации в 0, не мешало ему рассчитать еще и следующий кадр, который, по видимому, уже лежал в стеке.

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

На данный момент проблема выглядит неисправимой. Как мы справились? Поставили FPS таких анимаций в 20. Видимо, на таком FPS"е случая, когда юнити хочет просчитать два кадра за одну итерацию - не случается.

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

Что с этим делать - не ясно.