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

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

1я часть

Продолжаем делать наш Unity for dummies платформер.

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

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

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

Научим игрока двигаться

Создаём в панели ассетов C# cкрипт PlayerBehaviour, и запихиваем его в папку Scripts (её можно создать в той же панели ассетов).

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

Затем выбираем наш объект Player слева, в меню иерархии, и закрепляем инспектор (меню справа), нажав на замок в верхнем правом углу.

Пока закрываем все ненужные компоненты (Box Collider 2D, etc), нажимая на стрелочку у каждого из них.

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

Теперь перетаскиваем наш скрипт в инспектор, и он прикрепляется к объекту Player (если вы не выполнили предыдщуий пункт с закрепением меню, то вы этого сделать не сможете).

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

Если зайти в Edit => Project Settings => Input Manager, то мы можём увидеть настройки управления. Например, прыжок (Jump) назначен на пробел, в то время, как движение по горизонтали назначено на a, d, ←,→.

Запомним это для того, чтобы затем использовать в коде (названия инпутов Jump, Horizontal).

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

Пора покодить. Два раза нажимаем на наш скрипт PlayerBehaviour, и Unity отдаст его в руки Visual Studio.

Честно, данную IDE я не люблю. Потому я открываю его в VScode (а вы хоть в VIMе пишите - это ваш выбор).

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; // Физическое поведение (тело) объекта private Rigidbody2D rigidBody; private void Start() { // Получаем доступ к Rigidbody2D объекта Player rigidBody = gameObject.GetComponent<Rigidbody2D>(); } private void Update() { updatePlayerPosition(); } // Обновляем местоположение игрока private void updatePlayerPosition() { // Получаем значение ввода горизонтального перемещение float moveInput = Input.GetAxis("Horizontal"); // Получаем значение ввода прыжка float jumpInput = Input.GetAxis("Jump"); // Значения xVelocity, yVelocity можно задать через инспектор if (moveInput < 0) { // Движ влево rigidBody.velocity = new Vector2(-xVelocity, rigidBody.velocity.y); } else if (moveInput > 0) { // Движ вправо rigidBody.velocity = new Vector2(xVelocity, rigidBody.velocity.y); } if (jumpInput > 0) { //Тип прыгает rigidBody.velocity = new Vector2(rigidBody.velocity.x, yVelocity); } } }

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

Я не буду часто использовать try/catch в этом коде, но вам очень советую - сильно экономит время.

Пропустить ; - это святое 
Пропустить ; - это святое 

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

Мне не нравится, что персонажа переворачивает. Исправим.

Заходим в инспектор, открываем Rigidbody2D и ставим галочку на Freeze Rotation Z.

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

Проверяем

Жить можно, но есть проблема - камера не двигается за персонажем.

Учим камеру двигаться

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

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

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

2. Задать движение камеры за персонажем програмно.

Мой выбор =)

Создаём скрипт CameraBehaviour, и привязываем его к объекту Main Camera (добавляем через инспектор).

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

Открываем наш новый скрипт, и начинаем кодить (да, мне на работе не хватает, продолжаю и после).

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

Фиксируем объект камеры на замок в инспекторе, и перетаскиваем наш объект Player в GameObject.

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

Тестируем

Теперь камера двигается за игроком.

Однако камера постоянно вылезает за пределы уровня, показывая синий фон.

Ограничение движения камеры

Я не уверен, что моё решение правильное. Буду рад, если кто-нибудь поделится своими соображениями на данный счёт.

Если у камеры пропала рамка (у меня, внезапно, случилась такая оказия - потратил аж 2 минуты на решение проблемы), надо зайти в Gizmos и отметить чекбокс на камере.

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

Добавляем в наш скрипт CameraBehaviour следующий код:

[Header("Camera position restrictions")] public float minY; public float maxY; public float minX; public float maxX;

Двигаем камеру, и снимаем наши измерения ее положений.

На скрине ниже камера стоит в левом нижнем углу сцены.

Исходя из поля Position, я выбираю минимум по Х = -12, по Y = -0.5 (числа округлены их -12.09 и -0.84) соответсвенно.

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

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

Результат манипуляций с веерами
Результат манипуляций с веерами

Теперь обновим метод UpdateCameraPosition в скрипте CameraBehaviour

// Изменяем позицию камеры на экране 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); } }

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

Отлично, камера перестала "гулять". Работаем дальше.

Разучиваем персонажа летать

Всё бы хорошо, но наш персонаж может летать - надо всего лишь жать кнопку прыжка. Добавим проверку на нахождение на земле.

Выбираем наш Foreground, и создаём новый слой 'Ground' в инспекторе.

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

Снова тыкаем на Foreground, и выбираем в поле Layer наш только что созданный слой.

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

Переходим к коду.

Добавим в PlayerBehaviour такую строчку.

[SerializeField] private LayerMask ground;

Теперь в объекте Player мы можем выбрать наш свежесозданный слой.

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

Обновляем наш PlayerBehaviour. Добавим коллайдер (rigidBody мы создавали ранее).

// Физическое поведение (тело) объекта private Rigidbody2D rigidBody; // Коллайдер, проверка на столкновения private Collider2D coll; // Start (https://docs.unity3d.com/ScriptReference/MonoBehaviour.Start.html) private void Start() { // Получаем доступ к Rigidbody2D объекта Player rigidBody = gameObject.GetComponent<Rigidbody2D>(); coll = gameObject.GetComponent<Collider2D>(); }

Теперь мы можем обновить обработку перемещения персонажа в методе updatePlayerPosition

// Обновляем местоположение игрока private void updatePlayerPosition() { // Получаем значение ввода горизонтального перемещение float moveInput = Input.GetAxis("Horizontal"); // Получаем значение ввода прыжка float jumpInput = Input.GetAxis("Jump"); // Значения xVelocity, yVelocity можно задать через инспектор if (moveInput < 0) { // Движ влево rigidBody.velocity = new Vector2(-xVelocity, rigidBody.velocity.y); } else if (moveInput > 0) { // Движ вправо rigidBody.velocity = new Vector2(xVelocity, rigidBody.velocity.y); } else if (coll.IsTouchingLayers(ground)) { rigidBody.velocity = Vector2.zero; // Лично меня дико бесит инерция вбок при приземлении персонажа, отключаем } if (jumpInput > 0 && coll.IsTouchingLayers(ground)) { //Тип прыгает, если стоит на земле rigidBody.velocity = new Vector2(rigidBody.velocity.x, yVelocity); } }

Тут я вспомнил, что забыл глянуть, как "наделся" Box Collider на персонажа. Кажется, все ок - линии идут ровно по персонажу (жёлтая рамка). Если что, всегда можно ткнуть на Edit Collider и подтянуть его.

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

Тестируем

Летать мы разучились, а по платформе больше не скользим. Победа!

Я пока не знаю, как решить или улучшить

  • Из-за слоя Ground персонаж может прыгать от стенок. Не знаю, как это можно решить.
  • Является ли ограничение движения камеры, которое я написал, отимальным.
  • Иногда персонаж застревает на месте. Такое ощущение, что коллайдер видит какой то микропиксель, и персонаж застревает на нём.

Полный код

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 void Start() { // Получаем доступ к Rigidbody2D объекта Player rigidBody = gameObject.GetComponent<Rigidbody2D>(); coll = gameObject.GetComponent<Collider2D>(); } private void Update() { updatePlayerPosition(); } // Обновляем местоположение игрока private void updatePlayerPosition() { // Получаем значение ввода горизонтального перемещение float moveInput = Input.GetAxis("Horizontal"); // Получаем значение ввода прыжка float jumpInput = Input.GetAxis("Jump"); // Значения xVelocity, yVelocity можно задать через инспектор if (moveInput < 0) { // Движ влево rigidBody.velocity = new Vector2(-xVelocity, rigidBody.velocity.y); } else if (moveInput > 0) { // Движ вправо rigidBody.velocity = new Vector2(xVelocity, rigidBody.velocity.y); } else if (coll.IsTouchingLayers(ground)) { rigidBody.velocity = Vector2.zero; // Лично меня дико бесит инерция вбок при приземлении персонажа, отключаем } if (jumpInput > 0 && coll.IsTouchingLayers(ground)) { //Тип прыгает, если стоит на земле rigidBody.velocity = new Vector2(rigidBody.velocity.x, yVelocity); } } }

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