Создание основной механики игры Angry Birds на Unity
Начну с того, что я новичок в разаботке на Unity. Как и многие другие начинающие разработчики, мне хочется набраться опыта в создании игр на Unity на основе небольших проектов, копирующих механики всем знакомых игр. В этой небольшой статье я расскажу о своем опыте созадния основной механики стрельбы из рогатки из игры Angry Birds.
Игра Angry Birds
Я не буду вдаваться в подробности поиска спрайтов для моего проекта, т.к. не важно будут у вас «птички» или «кирпичи». Сосредоточимся на создании самой механики.
Заготовленная сцена
Я заранее немного подготовил сцену. Были созданны два объекта: Background и Ground. Для этих обектов добавил спрайты и для Ground добавил Box Collider 2D, чтобы настроить его коллизию.
Стрельба из рогатки будет основана на двух объектах:
Непосредственно птичка
Точка, к которой будет привязана наша птичка
Для начала создадим 2D объект круглой формы. Именно он и станет нашей птичкой. Назначим ему подходящий спрайт и разместим на подходящем месте.
Созданная птичка
Добавим к ней компоненты:
Добавленные компоненты
Теперь создадим точку привязи. Это будет просто пустой объект с названием «Point», к которому мы добавим компонент Rigidbody 2D и изменим его Body Type с «Dynamic» на «Static», чтобы объект не падал в пространстве.
Созданная точка привязи
Пора поговорить подробнее про Spring Joint 2D, который мы присоединили к птичке. Это 2D-компонент позволяет двум игровым объектам, управляемым Rigidbody 2D, соединяться вместе, как при помощи пружины. Пружина будет прикладывать усилие вдоль своей оси между двумя игровыми объектами, пытаясь удерживать их на определенном расстоянии друг от друга. Чтобы связать объекты, мы переносим Rigidbody 2D объекта Point в поле Connected Rigid Body.
Компонент Spring Joint 2D
Переносим птичку к точке привязи и вуаля — птичка подпрыгивает в воздухе как будто привязана пружиной к нашей точке.
Ожидаемый результат
Пришло время заняться скриптом для нашей птички.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Bird : MonoBehaviour
{
public Rigidbody2D birdRb;
public Rigidbody2D pointRb;
public float maxDist = 2f;
public bool isTouched = false;
// Start is called before the first frame update
void Start()
{
birdRb = GetComponent();
}
// Update is called once per frame
void Update()
{
if (isTouched)
{
Vector2 mousPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if(Vector2.Distance(mousPos, pointRb.position) > maxDist)
{
birdRb.position = pointRb.position + (mousPos - pointRb.position).normalized * maxDist;
}
else
{
birdRb.position = mousPos;
}
}
}
private void OnMouseDown()
{
isTouched = true;
birdRb.isKinematic = true;
}
private void OnMouseUp()
{
isTouched=false;
birdRb.isKinematic=false;
StartCoroutine(Fly());
}
IEnumerator Fly()
{
yield return new WaitForSeconds(0.1f);
gameObject.GetComponent().enabled = false;
this.enabled = false;
}
}
Если вы что-то не поняли, то ничего страшного. Сейчас мы подробно пройдемся по всему коду и разберемся, что есть что. Но если кратко, то наш код позволяет тянуть за птичку и запускать её в полет, а также запрещает утягивать птичку слишком далеко от нашей точки привязи.
Начнем с самого начала — переменных.
public Rigidbody2D birdRb;
public Rigidbody2D pointRb;
public float maxDist = 2f;
public bool isTouched = false;
Переменные birdRb и pointRb нужны нам, чтобы передавать в скрипт Rigidbody 2D наших объектов Bird и Point. Они нам понадабятся в дальнейшем коде.
Переменная maxDist нужна нам для определения максимального расстояния оттягивания птички от точки, к которой она привязана.
isTouched — флажок для определения того, нажали ли мы на птичку или нет.
Далее в коде у нас идут встроенные методы:
Start
Update
OnMouseDown
OnMouceUp
Также присутствует корутина Fly.
Метод Start вызывается в самом начале работы скрипта. В нем мы передаем значение переменной birdRb.
void Start()
{
birdRb = GetComponent();
}
В методе Update, вызывающемся каждый фрейм, находится условие, непозволяющее птичке выйти за пределы maxDist.
void Update()
{
if (isTouched)
{
Vector2 mousPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
if(Vector2.Distance(mousPos, pointRb.position) > maxDist)
{
birdRb.position = pointRb.position + (mousPos - pointRb.position).normalized * maxDist;
}
else
{
birdRb.position = mousPos;
}
}
}
Сначала мы проверяем, касается ли игрок птицы с помощью переменной-флага isTouched (строка 3). Далее, если птица все же находится под воздейстивем прикосновения, происходит считывание позиции мыши игрока (строка 5). После этого следует конструкция if-else, которая непозволяет вытянуть птицу за maxDist. Сначала идет проверка, вышел ли курсор мыши за maxDist (строка 7), и, если он вышел, то в бой входит формула с 9 строки. О ней поподробнее.
Часть кода (mousPos — pointRb.position).normalized созадет вектор с началом pointRb.position и концом в mousPos, а затем делает его длину равной единице с помощью .normalized. Далее мы умножаем этот вектор на maxDist, чтобы он был равен максимальному радиусу, на который мы можем оттянуть птичку и прибавляем его к начальной позиции. Таким образом мы получаем позицию птицы, максимально отдаленную от центра с сохранением нужного нам направления.
В случае того, если maxDist не была превышена, позиция птицы двигается вместе с курсором.
Перейдем к методам OnMouseDown и OnMouseUp. Это стандартные методы MonoBehaviour, вызывающиеся, когда игрок кликает (нажимает кнопку и отжимает соответственно) на объект с коллизией. В теле метода OnMouseDown поднимается флажок isTouched и переводит нашу птицу в состояние isKinematic, что позволяет игнорировать Spring Joint 2D.
private void OnMouseDown()
{
isTouched = true;
birdRb.isKinematic = true;
}
И в методе OnMouseUp, наоборот, флаг isTouched опускается, состояние isKinematic отключается, но также происходит запуск корутины Fly, позволяющей нашей птичке вылететь из «рогатки».
private void OnMouseUp()
{
isTouched=false;
birdRb.isKinematic=false;
StartCoroutine(Fly());
}
IEnumerator Fly()
{
yield return new WaitForSeconds(0.1f);
gameObject.GetComponent().enabled = false;
this.enabled = false;
}
Если вы хотите узнать о корутине больше, советую эту статью.
Разберемся с телом корутины. С помощью кода строки 13 мы отключаем компонент Spring Joint 2D у нашей птички, тем самым отвязывая ее от Point спустя 0.1 секунду, тем самым заставляя её отпружинить в противоположную от натягивания сторону. Затем мы отключаем скрипт, чтобы мы не могли перехватить птицу в полёте.
Результат подключения скрипта к Bird
Таким образом, мы повторили основную механику стрельбы из рогатки из игры Angry Birds. Надеюсь, эта статья была интересна и познавательна.
До встречи в следующих статьях.