Pull to refresh

Создание основной механики игры Angry Birds на Unity

Level of difficultyEasy
Reading time4 min
Views3.2K

Начну с того, что я новичок в разаботке на Unity. Как и многие другие начинающие разработчики, мне хочется набраться опыта в создании игр на Unity на основе небольших проектов, копирующих механики всем знакомых игр. В этой небольшой статье я расскажу о своем опыте созадния основной механики стрельбы из рогатки из игры Angry Birds.

Игра Angry Birds
Игра Angry Birds

Я не буду вдаваться в подробности поиска спрайтов для моего проекта, т.к. не важно будут у вас "птички" или "кирпичи". Сосредоточимся на создании самой механики.

Заготовленная сцена
Заготовленная сцена

Я заранее немного подготовил сцену. Были созданны два объекта: Background и Ground. Для этих обектов добавил спрайты и для Ground добавил Box Collider 2D, чтобы настроить его коллизию.

Стрельба из рогатки будет основана на двух объектах:

  • Непосредственно птичка

  • Точка, к которой будет привязана наша птичка

Для начала создадим 2D объект круглой формы. Именно он и станет нашей птичкой. Назначим ему подходящий спрайт и разместим на подходящем месте.

Созданная птичка
Созданная птичка

Добавим к ней компоненты:

  • Circle Collider 2D

  • Rigidbody 2D

  • Spring Joint 2D (Важный компонент, но о нем позже)

Добавленные компоненты
Добавленные компоненты

Теперь создадим точку привязи. Это будет просто пустой объект с названием "Point", к которому мы добавим компонент Rigidbody 2D и изменим его Body Type с "Dynamic" на "Static", чтобы объект не падал в пространстве.

Созданная точка привязи
Созданная точка привязи

Пора поговорить подробнее про Spring Joint 2D, который мы присоединили к птичке. Это 2D-компонент позволяет двум игровым объектам, управляемым Rigidbody 2D, соединяться вместе, как при помощи пружины. Пружина будет прикладывать усилие вдоль своей оси между двумя игровыми объектами, пытаясь удерживать их на определенном расстоянии друг от друга. Чтобы связать объекты, мы переносим Rigidbody 2D объекта Point в поле Connected Rigid Body.

Компонент Spring Joint 2D
Компонент 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<Rigidbody2D>();
    }

    // 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<SpringJoint2D>().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<Rigidbody2D>();
    }

В методе 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<SpringJoint2D>().enabled = false;
        this.enabled = false;
    }

Если вы хотите узнать о корутине больше, советую эту статью.

Разберемся с телом корутины. С помощью кода строки 13 мы отключаем компонент Spring Joint 2D у нашей птички, тем самым отвязывая ее от Point спустя 0.1 секунду, тем самым заставляя её отпружинить в противоположную от натягивания сторону. Затем мы отключаем скрипт, чтобы мы не могли перехватить птицу в полёте.

Результат подключения скрипта к Bird
Результат подключения скрипта к Bird

Таким образом, мы повторили основную механику стрельбы из рогатки из игры Angry Birds. Надеюсь, эта статья была интересна и познавательна.

До встречи в следующих статьях.

Tags:
Hubs:
Total votes 7: ↑7 and ↓0+7
Comments3

Articles