Про создание платформера на Unity. Часть первая, характерная
Все мы здесь любим качественные пошаговые руководства для начинающих, чего уж греха таить. По платформерам на Unity руководств много, а вот качественных не то что бы и очень. Сегодня мы попробуем добавить в копилку хороших уроков еще один. А создавать мы будем персонажа для 2D-платформера, ни больше, ни меньше.
Присоединяйтесь, учитесь, но помните: под катом очень много гифок.
Итак, с чего начать создание персонажа? Конечно же, с его спрайта. Достаточно перетащить картинку из любой папки на жестком диске во вкладку Assets, а оттуда — прямо на сцену. Оговорюсь сразу, в этом уроке мы не будем рассматривать создание анимации. А вот в следующих частях цикла — будем.
Как видите, после добавления на сцену (условимся, что это полноценный аналог словосочетанию scene view) у спрайта появились два компонента. Первый — transform. Он отвечает за расположение любого игрового объекта на сцене, его масштаб и текущий угол поворота относительно осей. Компонент sprite renderer как раз занимается отрисовкой спрайта нашего обаятельного носача в процессе редактирования и игры.
Но пока персонаж всего лишь картинка, он не может взаимодействовать с окружающим его миром. Для этого на помощь приходят компоненты, спрятанные во вкладке physics2d. В нашем случае это box collider и circle collider. Первый мы добавим на верхнюю часть персонажа для столкновений со стенами и всем остальным, а второй расположим на уровне ног. Это позволит двигаться по наклонным поверхностям (и поверхностям с небольшим перепадом высот) без особых проблем.
Теперь, чтобы на героя действовала, допустим, гравитация, добавим ему rigidbody2D (ну или твердое тело, как вам больше нравится). Для этого все в том же меню add component -> physics2D выберем пункт rigidbody2D и к спрайту сразу же добавится еще один компонент.
Если вкратце:
mass отвечает понятно за что;
linear drag и angular drag — линейное и угловое сопротивление, соответственно;
gravity scale — коэффициент гравитации для конкретно этого объекта;
fixed angle отключает переворот персонажа при столкновении с чем-нибудь, допустим, летящим;
isKinematic фиксирует объект раз и навсегда в одной точке;
interpolate устанавливает режим сглаживания при отрисовке персонажа;
Для платформера стандартное значение гравитации (-9.81 по оси Y) не очень подходит, поэтому изменим его на какое-нибудь магическое число. Например, -30. Для этого зайдем в Edit — Project Settings — Physics2D и заменим нужное значение в инспекторе.
На этом пока перестанем добавлять персонажу компоненты. Но сделаем кое-что из него. Для того, чтобы нам не приходилось тысячу раз добавлять одинаковые компоненты на каждом, допустим, уровне, в Unity есть механика под названием prefabs. Она позволяет создать из игрового объекта «болванку», которую можно использовать много раз и менять как своей душе угодно, не боясь за то, что какие-то экземпляры могут не измениться. Для создания префаба достаточно просто перетащить объект из иерарахии во вкладку assets. В моем случае еще и в папку prefabs.
Как видите, оба экземпляра героя прекрасно создаются и существуют вместе. Теперь нужно создать платформу, на которой будет стоять наш большеносый друг. Перетащим спрайт на сцену и добавим ему polygon collider. Размеры этого коллайдера, к слову, можно менять, перетаскивая его вершины с зажатой кнопкой shift.
Самое время научить персонажа двигаться. Перетащим заранее подготовленный скрипт (его нужно скачать и сохранить в папку assets) прямо на персонажа в hierarchy view.
У этого кусочка кода есть ряд параметров, которые отвечают за поведение героя в игре.
maxSpeed и JumpForce — максимальная скорость (по горизонтали) и сила прыжка. Экспериментально проверено, что для массы, равной единице, и гравитации -30 значения maxSpeed=10 и jumpForce = 700 являются оптимальными.
groundCheck — дочерний объект, находящийся в нижней точке спрайта и отвечающий за определение того, находится ли нечто, чем мы управляем, на «земле»
whatIsGround — что, собственно, считать землей. В нашем случае «землей» считается все, кроме персонажа
groundRadius — некая величина, в пределах которой проверяется столкновение с поверхностью.
В итоге, строчка grounded = Physics2D.OverlapCircle (groundCheck.position, groundRadius, whatIsGround); проверяет, пересекает ли groundCheck с радиусом groundRadius поверхность и, допустим, запрещает прыгать в нужных случаях.
Давайте, наконец, запустим игру и посмотрим что же у нас сегодня получилось. Для этого нажмем кнопку Play в верхн… Да ладно, вы и сами это разглядели 🙂
Герой прекрасно двигается (хотя, возможно, и не совсем прекрасно), и это создает для нас отличные предпосылки продолжить создание платформера.
А в следующей части мы разберемся как управлять камерой, узнаем кому нужно зажигание звезд и создадим самого первого врага. И да, попутно исправим один критический баг, беспечно пропущенный в статью во время этого урока. Догадаетесь, какой?
Если эта статья вдруг пробудила в вас желание написать собственную игру, то не растрачивайте его впустую! Прямо сейчас проходит конкурс, стать участником которого слишком просто: достаточно зарегистрироваться, выложить свою игру в store и дождаться объявления результатов. А победителей ждут Xbox One и великолепные Lumia 930!
Пойду дописывать свой Angry Flappy Swompy 3 Deluxe. Stay tuned, вторая часть статьи в ближайшие дни!
А вот и другие наши статьи по схожей тематике:
Источник статьи: http://habr.com/ru/company/microsoft/blog/236125/
Туториал 4: 2Д платформер (для новичков). Часть 1.
Введение:
1. Шаг
Запустите Unity и создайте новый 2D-проект.
2. Шаг
3. Шаг
4. Шаг
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerMove : MonoBehaviour <
//переменная для скорости движения
public float speed;
//ссылочная переменная для компонента Rigidbody2D
Rigidbody2D rb;
void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent Rigidbody2D > ();
>
void FixedUpdate () <
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -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;
>
>
5. Step
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;
void Start () <
//делаем ссылку на Rigidbody2D
rb = GetComponent Rigidbody2D > ();
>
//я буду использовать Update() для более точного определения прыжка
void Update () <
//проверка, нажат-ли прыжок и находится-ли крыса на земле
if ( Input .GetButtonDown ( «Jump» ) && isGrounded) <
//применяем силу на Rigidbody2D вдоль оси Y для прыжка
rb.AddForce ( Vector2 .up * jumpForce, ForceMode2D .Impulse);
//переключаем переменную, чтобы предотвратить следующий прыжок, или мы могли бы снова прыгнуть (до того, как isGrounded будет переключена в FixedUpdate ())
isGrounded = false;
>
>
void FixedUpdate () <
//изменяем переменную, зависящую от результата Physics2D.OverlapPoint
isGrounded = Physics2D .OverlapPoint (groundCheck.position, whatIsGround);
//декларация переменной с её инициализацией значением полученным с горизонтальной оси (значение лежит в области между -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;
>
>
6. Step
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 Rigidbody2D > ();
>
//я буду использовать 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);
>
7. Step
8. Шаг
9. Шаг
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerAnim : MonoBehaviour <
//ссылочная переменная для аниматора
Animator anim;
//ссылочная переменная для rigidbody2D
Rigidbody2D rb;
void Start () <
//делаем ссылку на аниматор
anim = GetComponent Animator > ();
//делаем ссылку на Rigidbody2D
rb = GetComponent Rigidbody2D > ();
>
void Update () <
//меняем параметр speed в Animator. Используем значение скорости по оси х
anim.SetFloat ( «speed» , Mathf .Abs (rb.velocity.x));
>
>
10. Шаг
11. Шаг
12. Шаг
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 Animator > ();
//делаем ссылку на Rigidbody2D
rb = GetComponent Rigidbody2D > ();
//делаем ссылку на PlayerMove
pm = GetComponent PlayerMove > ();
>
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
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerSound : MonoBehaviour <
//ссылочная переменная для звукового файла
public AudioClip footsteps;
//публичная функция, получим доступ к ней из аниматора
public void FootStepsAudio () <
//воспроизвести заданный звук на позиции крысы
AudioSource .PlayClipAtPoint (footsteps, transform.position);
>
>
14. Шаг
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);
>
>
15. Шаг
Выберите Ground в иерархии. Создайте prefab Ground (перетащите объект в Assets). Поместите prefab Ground в сцену, как следующую платформу.
Выберите Main Camera и сделайте её дочерним объектом Rat (перетащите Main Camera на Rat). Камера будет следовать за крысой.
Можете изменить X-position камеры на 0, чтобы убрать рывки при повороте.
Я думаю, этого достаточно для первой части. Надеюсь, что вторая часть будет готова в мае-июне (у меня сейчас мало времени).
Источник статьи: http://xrayisgray.de/sites/tutorial_4_ru.html