Как сделать движение в unity 2d. Пишем арканоид на Unity. Механика мяча и платформы

В второй главе о разработке игры на Unity мы добавим игрока и его врагов в сцену

Создание игрока в Unity

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

  1. Скорируйте картинку в папку "Textures"
  2. Создайте новый спрайт и назовите его "Player"
  3. Настройте спрайт так, чтобы он отображался в свойстве "Sprite" компонента "Sprite Renderer"

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

  1. Поместите игрока в слой "2 - Foreground"
  2. Измените масштаб на (0.2, 0.2, 1)

Теперь несколько слов о компонентах. Мы только что говорили о компоненте "Sprite Renderer". Если вы еще не заметил, объект игры состоит из нескольких компонентов, видимых в панели "Инспектор".

По умолчанию пустой объект игры выглядит так:


Этот объект имеет только один компонент: Transform . Этот компонент является обязательным и не может быть отключен или удален. Вы можете добавить к объекту столько компонентов, сколько захотите. Например, скрипты добавляются в качестве компонента. Большинство компонентов может быть включено или отключено пока существует объект.


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

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

Sprite Renderer является компонентом, который способен отображать спрайт-текстуру. Теперь, когда мы узнали о концепции компонента, давайте добавим один к игроку!

Добавляем бокс-коллайдер (Box Collider)

Нажмите на кнопку "Добавить компонент" объекта игрока. Выберите "Box Collider 2D". Вы можете увидеть коллайдер в редакторе "Сцена" зрения и настройки его размера в "Инспекторе" в поле "Размер" (Size).

Существует еще один способ редактирования бокс-коллайдера. Выберите игровой объект с помощью бокс-коллайдера и зажмите клавишу shift на клавиатуре. Вы увидите, что на бокс-коллайдере (зеленый прямоугольник ) появились четыре маленьких рычажка. Перетащите один из них, чтобы изменить форму бокс-коллайдера. Будьте осторожны, синий прямоугольник представляет собой компонент Transform вашего игрового объекта, а не коллайдер.

Мы будем устанавливать размер коллайдера равным (10, 10) .

Это слишком много для настоящего шмапа, но все же меньше, чем спрайт:


В настоящее время, этого вполне достаточно.

Совет : Если вы планируете создать шмап , вам придется уделить много времени настройке хитбоксов – они должны точно соответствовать маленькому элементу внутри игрового спрайта. Вы также можете изменить такой параметр коллайдера, как shape – например, с помощью "Circle Collider 2D". Благодаря Unity, его поведение при этом не меняется, но это позволяет немного улучить геймплей.

Сохраним объект игрок как префаб. Теперь у вас есть базовую сущность игрока!


2D полигональный коллайдер

Если вы хотите супер точный и произвольный формы хитбокс, воспользуйтесь компонентом Unity "Полигоннальный коллайдер 2D" (Polygon Collider 2D). Эффект от этого будет незначительный, но зато вы получите такую форму, какую вы хотите.

"Polygon Collider 2D" похож на остальные коллайдеры: вы можете изменять форму с помощью мышки в режиме "Scene". Для удаления точки зажмите cmd или ctrl , а чтобы отрегулировать положение точки или добавить ее в форму коллайдера, используйте shift

Магия Rigidbody

Последний компонент, необходимый для добавления на нашего игрока: "Rigidbody 2D". Это поможет физическому движку правильно задействовать объект в игровом пространстве. Более того, это позволит вам использовать столкновения в скрипте.

  1. Выберите объект Player в "Hierarchy".
  2. Добавьте компонент "Rigidbody 2D".

Теперь, нажмите кнопку "играть" и смотрите, что у нас вышло:

Корабль падает! И как падает! Передвайте привет нашей любимой силе тяжести. По мере того, как сменяются кадры с заранее заданной гравитацией и rigidbodies прибавляет объекту массы, корабль притягивается к нижней части экрана.

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

Гравитация может быть использована в любой игре, но нам она не нужна. К счастью, гравитацию на Rigidbody можн легко отключить. Просто установите "гравитационный масштаб" равным нулю. Вот и все, корабль снова летит. Не забудьте поставить галочку в окошке "Fixed Angles", чтобы предотвратить вращение корабля, обусловленное такой физикой.

Окончательные настройки:

Перемещение игрока

Настало время написать скриптик (вы ведь не думали, что все будет двигаться само)? Создайте в Unity C#-скрипт в папке "Scripts" и назовите это "PlayerScript". Откройте ваш любимый редактор или используйте подменю "Sync" (нажмите на "Assets" в строке меню, затем на "Sync MonoDevelop Project") для правки созданного Unity скрипта.

"Sync MonoDevelop Project" : Это подменю немного странное.Во-первых, невозможно изменить имя, даже если сменить редактора.
Мы также рекомендуем использовать это меню при создании первого скрипта, так как Unity создаст решения и привяжет их к библиотекам Unity (для Visual Studio, Xamarin Studio или MonoDevelop).
Если вместо этого вы просто откроете скрипт, компилятор вашего IDE, скорее всего, зарегистрирует определенные ошибки, не Unity. Это не имеет значения, потому что вам не придется использовать его напрямую, но функция автоматического завершения объектов Unity не помешает.

По умолчанию в скрипте уже прописаны методы Start и Update . Вот краткий список наиболее часто используемых функций:

  • Awake() вызывается один раз, когда объект создается. По сути аналог обычной функции-конструктора.
  • Start() выполняется после Awake() . Отличается тем, что метод Start() не вызывается, если скрипт не включен (remember the checkbox on a component in the "Inspector").
  • Update() выполняется для каждого кадра in the main game loop.
  • FixedUpdate() вызывается каждый раз через определеннок число кадров. Вы можете вызывать этот метод вместо Update() когда имеете дело с физикой ("RigidBody" и др.).
  • Destroy() вызывается, когда объект уничтожается. Это ваш последний шанс, чтобы очистить или выполнить код.

У вас также есть некоторые функции для обработки столкновений:

  • OnCollisionEnter2D(CollisionInfo2D info) выполняется, когда коллайдер объекта соприкасается с другим коллайдером.
  • OnCollisionExit2D(CollisionInfo2D info) выполняется, когда коллайдер объекта не соприкасается ни с одним другим коллайдером.
  • OnTriggerEnter2D(Collider2D otherCollider) выполняется, когда коллайдер объекта соприкасается с другим коллайдером с пометкой "Trigger".
  • OnTriggerExit2D(Collider2D otherCollider) выполняется, когда коллайдер объекта перестает соприкасаться с коллайдером, помеченным как "Trigger".

Итак, с теорией покончено, пора в бой. Или нет, погодите еще немного: обратите внимание, что почти все, о чем мы говорили с вами имеет, суффикс "2D". Box Collider 2D , a Rigidbody 2D , OnCollisionEnter2D , OnTriggerEnter2D и т.д. Эти новые компоненты или методы появились с Unity 4.3. Используя их, вы работаете с физическим движком, встроенным в Unity 4.3, для 2D-игр (на основе Box2D) вместо движка для 3D-игр (PhysX). Два движка имеют аналогичные концепции и объекты, но они не работают точно так же. Если вы начинаете работать с одним (например, Box2D для 2D-игр), придерживаqntcm его. Именно поэтому мы используем все объекты или методы с суффиксом "2D".

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

Using UnityEngine; /// /// Контроллер и поведение игрока /// public class PlayerScript: MonoBehaviour { /// /// 1 - скорость движения /// public Vector2 speed = new Vector2(50, 50); // 2 - направление движения private Vector2 movement; void Update() { // 3 - извлечь информацию оси float inputX = Input.GetAxis("Horizontal"); float inputY = Input.GetAxis("Vertical"); // 4 - движение в каждом направлении movement = new Vector2(speed.x * inputX, speed.y * inputY); } void FixedUpdate() { // 5 - перемещение игрового объекта rigidbody2D.velocity = movement; } }

Поясню цифры в комментариях к коду:

  1. Сначала определим публичную переменную, которая будет отображаться в окне "Инспектор". Это скорость, используемая для корабля.
  2. Сохраним движение для каждого кадра.
  3. Используем дефолтную ось, которую можно отредактировать в "Edit" -> "Project Settings" -> "Input" . При этом мы получим целые значения между [-1, 1] , где 0 будет означать, что корабль неподвижен, 1 - движение вправо, -1 - влево.
  4. Умножим направление на скорость.
  5. Изменим скорость rigidbody. Это даст движку команду к перемещению объекта. Сделаем это в FixedUpdate() , предназначенном для всего, что связано с физикой.
Заметка о соглашениях C# : Посмотрите на видимость speed члена класса – он обозначен как публичный. В C# переменная члена класса должна быть приватной для соответствующего сохранения его внутренней репрезентации.
Но смена типа переменной на публичный позволяет редактировать ее в Unity через панель "Inspector", даже в процессе игры. Это одна из самых мощных возможностей Unity, позволяющая изменять геймплей без использования кода.
Помните, что в данном случае мы создаем скрипты, а это не то же самое, что классическое программирование на C#. Это предполагает некоторых правил и соглашений.

Теперь добавим скрипт к игровому объекту. Для этого перетащите скрипт из окна "Проект" (Project) на игровой объект в "Иерархии" (Hierarchy). Вы также можете нажать на "Add Component" и добвить его вручную.

Нажмите кнопку "Play" в верхней части окна редактора. Корабль движется! Congratulations, Вы только что сделали эквивалент "Hello, World!" для игры:)

Попробуйте настроить скорость: нажмите на игрока, измените значения скорости в "Инспекторе", и посмотрите что из этого получится.

Будьте осторожны: изменения параметров, сделанные во время, игры теряются, когда вы ее остановите! Инспекторе - это отличный инструмент для настройки геймплея, но запомните или запишите, что вы делали, если хотите сохранить изменения. Этот же трюк подходит, если вы хотете проверить что-то новое, но не хотите вносить изменения в реальный проект.

Первый враг

Теперь добавим неприятелей, стремящихся уничтожить наш корабль. Пусть им будет зловещий спрут, названный "Poulpi":


Создадим новый спрайт. Для этого:

  1. Скопируйте картинку в папку "Textures".
  2. Создайте новый спрайт, используя это изображение.
  3. Измените свойство "Масштаб" (Scale) в разделе Трансформирование (Transform) на (0.4, 0.4, 1) .
  4. Добавьте "Box Collider 2D" размером (4, 4) .
  5. Add a "Rigidbody 2D" with a "Gravity Scale" of 0 and "Fixed Angles" ticked.

Сохраните префаб и... вуаля!


Скрипт

Теперь напишем простенький скрипт, отвечающий за движение осьминога в определенном направлении. Для этого создайте новый скрипт, назвав его "MoveScript".

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

Скопируем некоторые части кода, который мы написали в «PlayerScript" для движения персонажа. We will add another designer (a public member you can alter in the "Inspector") variable for the direction:

Using UnityEngine; ///

/// Просто перемещает текущий объект игры /// public class MoveScript: MonoBehaviour { // 1 - переменные /// /// Скорость объекта /// public Vector2 speed = new Vector2(10, 10); /// /// Направление движения /// public Vector2 direction = new Vector2(-1, 0); private Vector2 movement; void Update() { // 2 - Перемещение movement = new Vector2(speed.x * direction.x, speed.y * direction.y); } void FixedUpdate() { // Применить движение к Rigidbody rigidbody2D.velocity = movement; } }

Прикрепите скрипт к осьминогу. Нажмите "Play" и убедитесь, что спрут движется так, как показано на рисунке ниже:

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

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

Итак. Всем привет. И сегодня я расскажу, как сделать простое движение персонажа. Сейчас только от третьего лица... Приступим...
Начнём, пожалуй, с создания персоажа. У меня это будет куб. Кто не знает, как создавать кубы или круги, поясняю - "GameObject" => "CreateOther" => "Cube". Создаём таким же образом камеру и привязываем к кубу (то бишь просто в иерархии перетаскиваем камеру на куб).
Так... Теперь создадим поверхность, по которой персонаж будет ходить. Пусть это будет просто "Plane". Ах, да... В конце урока будет ссылка с исходником по туториалу для тех, кто не понял.
Итак. Теперь создадим скрипт "Move". Добавим переменную игрока и переменную скорости.

Public GameObject player;
public int speed = 5;


Теперь укажем в методе старта, что это объект, на котором висит скрипт.

Void Start () {
player = (GameObject)this.gameObject;
}


Теперь сделаем само передвижение игрока вперёд при нажатии на "W" или стрелку вверх. Это делаем в методе void Update()! Для этого мы будем прибавлять позицию. Например вперёд.

If (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
}


Мы прибавили позицию вперёд (forward) и умножили на скорость, а точнее её переменную. И обязательно надо умножить на кадры в секунду (deltaTime).
Таким же образом сделаем движение назад. Только будем отнимать позицию.

If (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
}


Таким же образом можем сделать и вправо и влево (right, left), но я сделаю просто поворот игрока, при нажатии на "A" или "D".
Я буду использовать "Rotate()". Чтобы поворачивать по оси "Y", я буду использовать "up" и "down". Кстати, для этого ещё надо объявить переменную "public int speedRotation = 3". И пишем в условиях.

If (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
player.transform.Rotate(Vector3.down * speedRotation);
}
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
player.transform.Rotate(Vector3.up * speedRotation);
}


Ну... Сейчас пришло время анимировать. Я записываю анимацию в самой юнити. Это можно открыть в "Window" => "Animation". В этом окне мы можем анимировать куб. Итак... Пропустим момент создания анимации. Давайте теперь создадим переменную анимации.

Public AnimationClip anima;


Теперь в старте добавим клип.

Animation.AddClip(anima, "animCube");


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



Итак... У нас получился хороший код. Сейчас мы сделаем прыжок. Всё так же просто. Опять мы будем прибавлять позицию. Только вверх (up).
И так же с новой переменной анимации "public AnimationClip anima2;"? так же добавим и переменной "public int jumpSpeed = 50;". И мы получаем условие.

If (Input.GetKeyDown(KeyCode.Space))
{
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
}


Всё... Наш код готов.

using UnityEngine;
using System.Collections;
public class Move: MonoBehaviour {
public GameObject player;
public int speedRotation = 3;
public int speed = 5;
public AnimationClip anima;
public int jumpSpeed = 50;

Void Start () {
player = (GameObject)this.gameObject;
animation.AddClip(anima, "animCube");
}
void Update(){
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
{
player.transform.position += player.transform.forward * speed * Time.deltaTime;
animation.CrossFade("animCube");
}
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
{
player.transform.position -= player.transform.forward * speed * Time.deltaTime;
}
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
{
player.transform.Rotate(Vector3.down * speedRotation);
}
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
{
player.transform.Rotate(Vector3.up * speedRotation);
}
if (Input.GetKeyDown(KeyCode.Space))
{
player.transform.position += player.transform.up * jumpSpeed * Time.deltaTime;
}

  • Tutorial

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

Загрузим сцену из первой части. Напомню, что в прошлый раз мы импортировали несколько спрайтов в папку 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 , то вы увидите, что во время покоя работает анимация Idle (бегает синий прогрессбар), а во время бега происходит переход на анимацию Run , и, соответственно, работает она.

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

Введение:

В этом уроке мы сделаем простой 2D платформер на движке Unity. В туториале будет использоваться встроенная физика2D. Также я хочу показать основы анимации (мы будем работать с листами спрайтов). Для этого урока вам понадобятся несколько разных файлов, таких как спрайты, звуки. Вы можете скачать архив.zip .

1. Шаг

Запустите Unity и создайте новый 2D-проект.

2. Шаг

Сначала создайте землю для нашей игры. Импортируйте largeGround из загруженного архива ( ссылка снова, если ещё не скачали. Распакуйте архив.zip после его загрузки).

Перетащите largeGround в сцену. Переименуйте созданный игровой объект как Ground . Проверьте, что Z-позиция равна нулю (измените её на 0 , если отличается). Добавьте к нему Box Collider 2D.

3. Шаг

Теперь мы можем сделать игрока. Для этого у меня есть лист спрайтов с крысой. Импортируйте ratIdle (из скаченного архива) в окно Assets . Нам надо разделить спрайты. Выберите ratIdle и переключите Sprite Mode на Multiple . Нажмите Apply .

Нажмите на Sprite Editor и новое окно будет открыто. Нажмите Slice . Измените Type на Grid By Cell Count . Установите Column на 4 и Row на 5 . Нажмите на кнопку Slice . Нажмите на Apply . Закройте это окно.

Раскройте спрайт. В нем должно быть теперь 20 кадров. Перетащите первый кадр в сцену. Будет создан новый игрвой объект. Выделите этот объект и назовите его Rat . Посмотрите на его Inspector . Измените Tag на Player . Убедитесь, что его Z-позиция 0. Добавьте к нему Capsule Collider 2D . Измените Direction на Horizontal . Нажмите на кнопку Edit и настройте размер коллайдера (тяните за зеленые точки). Теперь добавьте Rigidbody 2D . Установите Interpolate на Interpolate . Разверните Constraints и включите Freeze Rotation Z .

4. Шаг

Для крысы нужен скрипт движения. Создайте новый C# скрипт (правый клик в Assets) и назовите его PlayerMove . Для движения будем использовать встроеннную физику 2Д, то-есть будем использовать Rigidbody2D . Мы можем изменять скорость в зависимости о данных, полученных от Input Manager (я надеюсь, вы смотрели предыдущие туториалы и мне не надо будет повторяться). Откройте PlayerMove скрипт.

using System.Collections;

using UnityEngine;


public float speed;

Rigidbody2D rb;

void Start () {

rb = GetComponent ();
}

void FixedUpdate () {








rb.velocity = move;
}
}

Выберите крысу в иерархии и добавьте к ней скрипт PlayerMove . Измените переменную Speed (около 3). Вы можете запустить игру и проверить сцену. Крыса должна двигаться влево и вправо (использовать левую/правую стрелку или A/D).

5. Step

Теперь мы можем добавить прыжок крысе. Мы будем применять силу вдоль оси Y для прыжка. Смотрите Unity Manual для подробностей. Сила не должна добавляться каждый раз, когда нажимается кнопка прыжка, или крыса полетит как ракета. Также нам понадобится логическая переменная для управления прыжком. И нам нужна функция для переключения этой переменной относительно положения крысы к земле. Есть очень много способов достичь этого (триггер, raycast, таймер или что-то еще). Мы будем использовать Physics2D.OverlapPoint , чтобы определить, какой слой находится под контрольной точкой. Смотрите Unity Manual для деталей. Откройте PlayerMove скрипт снова.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour {






public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;

void Start () {
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
}


void Update () {




//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
}
}

void FixedUpdate () {
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint

//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis ("Horizontal" );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//y: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//Изменить скорость игрока на вычисленный вектор
rb.velocity = move;
}
}

Выберите Rat в иерархии, щелкните по нему правой кнопкой мыши и выберите Create Empty . Выберите этот созданный объект и переименуйте его в GroundCheck .

Выберите GroundCheck и включите иконку для лучшей видимости (смотрите скриншот). Включите moving tool и передвиньте GroundCheck под крысу, но не в сам коллайдер крысы. Убедитесь, что его Z-Position равна 0.

Выберите Ground в иерархии и смените Layer на Ground (добавьте новый Layer с этим названием, если в списке нет такого).

Выделите Rat в иерархии. В компоненте PlayerMove есть теперь новые поля. Включите Ground в whatIsGround . Поместите GroundCheck в поле GroundCheck . Измените JumpForce на 5.

Проверьте игру. Крыса должна теперь двигаться налево/направо и прыгать.

6. Step

Крыса должна уметь поворачиваться. Нам нужна функция для этого. В этой функции мы будем проверять значение "Horizontal" оси в Input Manager и поворачивать крысу в зависимости от этого значения. Для поворота будем использовать обратное значение x Scale в Transform компоненте. Откройте PlayerMove скрипт.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMove: MonoBehaviour {

//в инспекторе мы можем выбрать, какие слои будут землёй
public LayerMask whatIsGround;
//позиция для проверки касания земли
public Transform groundCheck;
//переменная, которая будет true, если крыса находится на земле
public bool isGrounded;
//значение величины силы
public float jumpForce;
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
//переменная контроля направления крысы
public bool isLookingLeft;

void Start () {
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
}

//я буду использовать Update() для более точного определения прыжка
void Update () {
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if (Input .GetButtonDown ("Jump" ) && isGrounded) {
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce (Vector2 .up * jumpForce, ForceMode2D .Impulse);
//sпереключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
}
}

void FixedUpdate () {
//изменяем переменную, зависит от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -1 и 1)
float x = Input.GetAxis ("Horizontal" );
//декларация локального вектора и инициализация посчитанным значением
//x: значение от InputManager * speed
//: принять текущее значение, мы не будем его менять, из-за использования силы тяжести
//z: должно быть равно нулю, нам не нужно движение по оси Z
Vector3 move = new Vector3 (x * speed, rb.velocity.y, 0f );
//изменить скорость игрока на вычисленный вектор
rb.velocity = move;

if (x < 0 && !isLookingLeft)

TurnTheRat ();
//проверка, совпадает ли направление взгляда с направлением движения
if (x > 0 && isLookingLeft)
//вызов функции поворота крысы, если проверка совпала
TurnTheRat ();
}

//функция поворота крысы
void TurnTheRat ()
{
//смена переменной показывающей направление взгляда на обратное значение
isLookingLeft = !isLookingLeft;
//поворот крысы через инвертацию размера по оси х
transform.localScale = new Vector3 (transform.localScale.x * -1 , transform.localScale.y, transform.localScale.z);
}

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

Крыса может теперь бежать влево и вправо и менять направление взгляда. Вы можете проверить сцену.

7. Step

Теперь можем начать анимировать крысу. Выберите Rat в иерархии и добавьте Animator к ней.

Создайте Animator Controller в Assets . Назовите его RatAnimator .

Выберите Rat и добавьте RatController в поле Controller .

Нам понадобится окно Animation . Включите его в меню Window м поместите его там, где вам удобно (я поместил над Assets ).

Выберите Rat в иерархии. Создайте новую анимацию (нажмите на кнопку Create ). Назовите эту новую анимацию IdleRatAnimation .

Теперь можем добавить спрайтовый лист. Выделите Rat в иерархии. Разверните ratIdle спрайт. Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key Animation

Включите окошко Animator в меню Window .

Анимация должна быть зацикленна. Убедитесь в этом на всякий случай. Перейдите к окну Animator и сделайте двойной клик на IdleRatAnimation Проверьте Loop Time .

У крысы есть теперь анимация покоя. Запустите сцену и проверьте.

8. Шаг

Теперь создадим анимацию бега. Импортируйте спрайт ratRun в Assets . Смените Sprite Mode на Multiple . Перейдите в Sprite Editor и переключите на Grid By Cell Count и установите Column 4 , Row 5 (смотрите 3. Шаг ). Выделите Rat в иерархии. Перейдите в окно Animations и нажмите на IdleRatAnimation потом нажмите на Create New Clip . Назовите новую анимацию RunRatAnimations .

Раскройте спрайт ratRun и выделите все 20 кадров (нажмите первый кадр, держите кнопку шифт и нажмите последний кадр). Перетащите все кадры в окошко Animations . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

Откройте окно Animator (включите его в меню Window , если не видите его).

IdleRatAnimation стандартная анимация. Нам нужны transition (переходы) к другим анимациям и параметры контроля этих transition. Нажмите на закладку Parameters . Добавьте новый float speed параметр. Сделайте правый клик на IdleRatAnimation и сделайте transition из IdleRatAnimation в RunRatAnimation . Потом правый клик на RunRatAnimation и добавьте transition на IdleRatAnimation .

Выберите transition от IdleRatAnimation к RunRatAnimation . Отключите Has Exit Time speed greater 0.01 .

Выберите transition от RunRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте новое condition (условие). Измените его на speed less 0.01 .

Анимация бега сейчас слишком медленная. Выберите RunRatAnimation в Animator и измените скорость на 2.5 (можете потом настроить по желанию).

9. Шаг

Нам нужен скрипт для смены условий в Animator . Мы могли бы добавить новые команды в скрипт PlayerMove , но для тренировки сделаем новый скрипт и с него получим нужные доступы. Мы будем проверять двигается ли крыса, и менять анимации в зависимости от движения. Создайте новый С# скрипт и назовите его PlayerAnim .

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


Animator anim;

Rigidbody2D rb;

void Start () {
//делаем ссылку на аниматор
anim = GetComponent ();
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
}

void Update () {
//меняем параметр speed в Animator. Используем значение скорости по оси х

}
}

Добавьте этот скрипт к крысе Rat .

Запустите сцену. У крысы должна появиться анимация бега

10. Шаг

Теперь сделаем анимацию прыжка. Выберите Rat в иерархии. Добавьте новую анимацию (в окошке Animation ) и назовите её JumpRatAnimation .

Я не сделал анимацию прыжка, просто используем замедленную анимацию бега. Выделите Rat в иерархии. Проверьте в окошке Animation , что JumpRatAnimation выбранна. Разверните спрайт ratRun . Надо выделить все кадры. Выберите первый кадр, зажмитеShift-Key и выделите последний кадр. Все 20 кадров должны выбраться. Перетащите все кадры в окошко Animation . Установите samples на 20. Сделайте двойной клик на первом кадре, чтобы сделать правильную длину анимации (возможно баг моей версии).

11. Шаг

Переключитесь на Animator . Нам нужно условие для анимации прыжка. Добавьте новую Bool и назовите её isJumping . Сделайте теперь transition (переход) (правый клик) из Any State к JumpRatAnimation . Добавьте transition от JumpRatAnimation к IdleRatAnimation .

Выделите transition от Any State к JumpRatAnimation . Отключите Has Exit Time . Разверните Settings и отключите Can Transition To (чтобы избежать перезапуска анимации, пока isJumping true). Добавьте condition (условие) isJumping true .

Выберите transition от JumpRatAnimation к IdleRatAnimation . Отключите Has Exit Time . Добавьте condition isJumping false .

Выделите JumpRatAnimation и измените Speed на 0.5. Замедленная анимация бега должна заменить анимацию прыжка.

12. Шаг

Нужен скрипт для контроля анимации прыжка. Откройте скрипт PlayerAnim . Из этого скрипта мы сделаем доступ на скрипт PlayerMove и сможем проверить переменную isGrounded . Если крыса не будет на земле, то сменим анимацию на анимацию прыжка. Также анимация прыжка будет включена при падении крысы.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerAnim: MonoBehaviour {

//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
//ссылочная переменная для PlayerMove
PlayerMove pm;

void Start () {
//делаем ссылку на Animator
anim = GetComponent ();
//делаем ссылку на Rigidbody2D
rb = GetComponent ();
//делаем ссылку на PlayerMove
pm = GetComponent ();
}

void Update () {
//проверка, находится ли крыса на земле
if (pm.isGrounded) {
//меняем параметр isJumping на false
anim.SetBool ("isJumping" , false );
//меняем параметр speed. Используем абсолютное значение вектора скорости по х
anim.SetFloat ("speed" , Mathf .Abs (rb.velocity.x));
// если крыса не на земле
} else {
//меняем параметр speed на 0
anim.SetFloat ("speed" , 0 );
//меняем параметр isJumping на true
anim.SetBool ("isJumping" , true );
}
}

Можете проверить сцену.

13. Step

Теперь добавим звуки шагов. Нам нужна функция для проигрывания звука. Вызывать функцию будем через аниматор. Создайте новый C# скрипт и назовите его PlayerSound .

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

//ссылочная переменная для звукового файла
public AudioClip footsteps;





}
}

Выберите Rat в иерархии и добавьте этот скрипт к крысе. Импортируйте аудио-файл ratStep . И добавьте ratStep в Footsteps поле компонента PlayerSound .

Выделите Rat в иерархии и перейдите в Animation . Смените анимацию на RunRatAnimation . Выберите кадр, когда хотите воспроизвести звук (кликните на полоску времени). Нажмите на Add Event (смотрите скриншот). Выберите добавленный Animations Event и установите Function на FootStepsAudio() .

14. Шаг

Теперь добавим звук после прыжка. Используем OnCollisionEnter2D для этого. Смотрите Unity Manual для деталей. Откройте скрипт PlayerSound .

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerSound: MonoBehaviour {

//ссылочная переменная для аудио-файла
public AudioClip footsteps;

//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () {
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
}

//запустится если было касание другого Collider2D
void OnCollisionEnter2D (Collision2D coll) {
//проверка тэга на тэг "Ground"
if (coll.gameObject.tag == "Ground" ) {
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
}
}

Выберите Ground в иерархии. Добавьте новый тэг Ground и измените тэг объекта Ground на тэг Ground .

15. Шаг

Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets ). Поместите prefab Ground в сцену, как следующую платформу.

Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat ). Камера будет следовать за крысой.

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

Скачать готовый проект