Популярное
Свежее
Моя лента
Сообщения
Рейтинг
Пополнить Steam
Низкая комиссия
Темы
Игры
Офтоп
Гайды
Ночной музпостинг
Вопросы
Hollow Knight
Музыка
Творчество
Кино и сериалы
Арт
Показать все
DTF
О проекте
Правила
Реклама
Приложения
Аккаунт удален
07.11.2020

Статья удалена

  • 1я часть
  • 2я часть
  • 3я часть

Полные версии кода будут находиться в конце поста.

В данном посте я напишу менеджер анимаций персонажа, и научу его прыгать и падать.

Пишем менеджер анимаций

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

animatorComponent.SetInteger("state", 1)

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

Использование enum (перечисление) - самое то для нашей задачи.

docs.microsoft.com
Enumeration types - C# reference

Кратко объясню, как enum работает.

При помощи ключевого слова enum создаётся список. В котором, по-умолчанию, элементы нумеруются от нуля.

// 0 1 2 3 enum Colors{ blue, white, black, white };

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

using System; public class Program { enum List{ zero, one, two, three, magicNumber = 42}; public static void Main() { List zero = List.zero; // Преобразование List.zero в int (целое число) int zeroNumber = (int)List.zero; List three = List.three; int threeNumber = (int)List.three; List magicNumber = List.magicNumber; Console.WriteLine(zero); // Output: zero Console.WriteLine(zeroNumber); // Output: 0 Console.WriteLine(three); // Output: three Console.WriteLine(threeNumber); // Output: 3 Console.WriteLine(magicNumber); // Output: magicNumber Console.WriteLine((int)magicNumber); // Output: 42 } }

В нём я задал значение 42 для magicNumber, то есть при преобразовании magicNumber в int, результатом будет 42.

Если хотите, можете поиграть с кодом в специальном C# фиддле.

dotnetfiddle.net
C# Online Compiler | .NET Fiddle

Используем enum для нашего менеджера анимаций.

Для этого создадим новый список AnimationState в PlayerBehaviour.

// 0 1 2 3 private enum AnimationState { idle, running, jumping, falling }; // Значением по-умолчанию ставим idle (0), как мы и задавали в аниматоре private AnimationState currentAnimationState = AnimationState.idle;

После этого можно обновить метод updatePlayerPosition + создадим метод setAnimationState, который и будет выбирать текущую анимацию.

// Обновляем местоположение игрока private void updatePlayerPosition() { float moveInput = Input.GetAxis("Horizontal"); float jumpInput = Input.GetAxis("Jump"); if (moveInput < 0) { // Влево rigidBody.velocity = new Vector2(-xVelocity, rigidBody.velocity.y); spriteRenderer.flipX = true; } else if (moveInput > 0) { // Вправо rigidBody.velocity = new Vector2(xVelocity, rigidBody.velocity.y); spriteRenderer.flipX = false; } else if (coll.IsTouchingLayers(ground)) { rigidBody.velocity = Vector2.zero; // Отключение инерции в стороны } if (jumpInput > 0 && coll.IsTouchingLayers(ground)) { rigidBody.velocity = new Vector2(rigidBody.velocity.x, yVelocity); } setAnimationState(); } // Выбираем текущую анимацию private void setAnimationState() { // Персонаж касается земли if (coll.IsTouchingLayers(ground)) { // При помощи Mathf.Abs получаем модуль значения ускорения (если бежим влево, оно отрицательное) // Если оно больше 0.1 (не стоим на месте), то персонаж бежит if (Mathf.Abs(rigidBody.velocity.x) > 0.1f) { currentAnimationState = AnimationState.running; } else { // Если нет - стоим на месте currentAnimationState = AnimationState.idle; } } // Изменияем значение state в аниматоре animatorComponent.SetInteger("state", (int)currentAnimationState); }

Проверим, не поломали ли чего.

Все работает, ничего не поломано =)

Добавляем анимации прыжка и падения

Находим нужные нам спрайты по пути Assets/BayatGames/Free Platform Game Assets/Character/Character Animation ( Update 1.8 )/Jump/1x.png

Нарезаем, как делали это ранее.

Статья удалена

Создаём анимации jump и fall, затем перетаскиваем их на игрока, чтобы они у нему привязались.

Статья удалена

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

Статья удалена

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

Прыжок (1x_0)

Статья удалена

Падение (1x_1)

Статья удалена

Анимации созданы, переходим в Animator.

Статья удалена

Создаём связи, как на скрине ниже.

Статья удалена

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

Статья удалена

Теперь проставляем условия для каждой связи.

Статья удалена

Напоминаю:

  • 0 - idle
  • 1 - run
  • 2 - jump
  • 3 - fall

Список условий

  • idle => run , если state Equals 1 (проставляли в прошлой части)
  • run => idle, если state Equals 0 (проставляли в прошлой части)
  • run => jump, если state Equals 2
  • jump => run, если state Equals 1
  • idle => jump, если state Equals 2
  • jump => idle, если state Equals 0
  • jump => fall, если state Equals 3
  • fall=> idle, если state Equals 0

Теперь зададим доп условия для новых значений в методе setAnimationState из скрипта PlayerBehaviour.

// Выбираем текущую анимацию private void setAnimationState() { // Персонаж касается земли if (coll.IsTouchingLayers(ground)) { // При помощи Mathf.Abs получаем модуль значения ускорения (если бежим влево, оно отрицательное) // Если оно больше 0.1 (не стоим на месте), то персонаж бежит if (Mathf.Abs(rigidBody.velocity.x) > 0.1f) { currentAnimationState = AnimationState.running; } else { // Если нет - стоим на месте currentAnimationState = AnimationState.idle; } // Персонаж не касается земли } else { // Ставим текущей анимацией прыжок currentAnimationState = AnimationState.jumping; if (currentAnimationState == AnimationState.jumping) { // Если усорение уходит в отрицательное значение, значит персонаж падает вниз if (rigidBody.velocity.y < .1f) { currentAnimationState = AnimationState.falling; } } else if (currentAnimationState == AnimationState.falling){ // Если он коснулся земли, то персонаж переходит в состояние спокойствия if (coll.IsTouchingLayers(ground)) { currentAnimationState = AnimationState.idle; } } } // Изменияем значение state в аниматоре animatorComponent.SetInteger("state", (int)currentAnimationState); }

Проверяем работу скрипта.

Похоже, всё в порядке, анимации работают.

В следующий раз попробуем добавить сбор предметов и выведение счёта.

Полный код

PlayerBehaviour

using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerBehaviour : MonoBehaviour { /** ** Ускорение игрока **/ [Header("Player velocity")] // Ось Ox public int xVelocity = 5; // Ось Oy public int yVelocity = 8; [SerializeField] private LayerMask ground; private Rigidbody2D rigidBody; private Collider2D coll; private SpriteRenderer spriteRenderer; private Animator animatorComponent; private enum AnimationState { idle, running, jumping, falling }; private AnimationState currentAnimationState = AnimationState.idle; private void Start() { rigidBody = gameObject.GetComponent<Rigidbody2D>(); coll = gameObject.GetComponent<Collider2D>(); spriteRenderer = gameObject.GetComponent<SpriteRenderer>(); animatorComponent = gameObject.GetComponent<Animator>(); } private void Update() { updatePlayerPosition(); } // Обновляем местоположение игрока private void updatePlayerPosition() { float moveInput = Input.GetAxis("Horizontal"); float jumpInput = Input.GetAxis("Jump"); if (moveInput < 0) { // Влево rigidBody.velocity = new Vector2(-xVelocity, rigidBody.velocity.y); spriteRenderer.flipX = true; } else if (moveInput > 0) { // Вправо rigidBody.velocity = new Vector2(xVelocity, rigidBody.velocity.y); spriteRenderer.flipX = false; } else if (coll.IsTouchingLayers(ground)) { rigidBody.velocity = Vector2.zero; // Отключение инерции в стороны } if (jumpInput > 0 && coll.IsTouchingLayers(ground)) { rigidBody.velocity = new Vector2(rigidBody.velocity.x, yVelocity); } setAnimationState(); } // Выбираем текущую анимацию private void setAnimationState() { // Персонаж касается земли if (coll.IsTouchingLayers(ground)) { // При помощи Mathf.Abs получаем модуль значения ускорения (если бежим влево, оно отрицательное) // Если оно больше 0.1 (не стоим на месте), то персонаж бежит if (Mathf.Abs(rigidBody.velocity.x) > 0.1f) { currentAnimationState = AnimationState.running; } else { // Если нет - стоим на месте currentAnimationState = AnimationState.idle; } // Персонаж не касается земли } else { // Ставим текущей анимацией прыжок currentAnimationState = AnimationState.jumping; if (currentAnimationState == AnimationState.jumping) { // Если усорение уходит в отрицательное значение, значит персонаж падает вниз if (rigidBody.velocity.y < .1f) { currentAnimationState = AnimationState.falling; } } else if (currentAnimationState == AnimationState.falling){ // Если он коснулся земли, то персонаж переходит в состояние спокойствия if (coll.IsTouchingLayers(ground)) { currentAnimationState = AnimationState.idle; } } } // Изменияем значение state в аниматоре animatorComponent.SetInteger("state", (int)currentAnimationState); } }

CameraBehaviour (в этой части не изменялся)

using System; using System.Collections; using System.Collections.Generic; using UnityEngine; public class CameraBehaviour : MonoBehaviour { // Добавляем объект, за которым будет двигаться камера [Header("GameObject")] // Пишу с нижним подчеркиванием, так gameObject - ключевое слово Unity. // а придумывать новое название переменной мне влом (сорян) public Transform _gameObject; [Header("Camera position restrictions")] public float minY; public float maxY; public float minX; public float maxX; void Update() { UpdateCameraPosition(); } // Изменяем позицию камеры на экране void UpdateCameraPosition() { try { transform.position = new Vector3( // Положение игрового объекта, за которым мы двигаемся Mathf.Clamp(_gameObject.position.x, minX, maxX), Mathf.Clamp(_gameObject.position.y, minY, maxY), // Положение камеры z должно оставать неизменным transform.position.z // (если камеры куда-то проваливается, заменить на, например, -10) ); } catch (Exception error) { // Ловим ошибку, если по каким то причинам код не может быть выполнен (например, забыли подставить объект в _gameObject) Debug.LogError(error); } } }

#unity