Tower Defence на движке Unity — Часть 2

Всем привет! Это вторая часть урока для новичков о том, как создать маленькую игру жанра Tower Defence на движке Unity. Мы остановились на создании скрипта для спауна крипов. Если интересно, прошу под кат.
5bd743dd5fb74cb080533dad77e77589.jpg

Часть 1 Часть 2

Скрипт «Spawner»


Вот так выглядит шаблон кода при создании нового скрипта:
using UnityEngine;

public class Spawner : MonoBehaviour
{
   void Start()
   {
   }
   
   void Update()
   {
   }
}

Объявим публичную переменную хранящую образец объекта для клонирования.
public GameObject spawnObject;

Перейдём в редактор Unity, и перетащим скрипт на объект Spawner.
c9538ee573e64df6b7f74b16727b04ac.jpg

Этими действиями мы привязали скрипт к объекту. Так как переменная spawnObject с публичным модификатором, её мы сможем изменять прямо в редакторе Unity через окно инспектора.
28769f14c7a5490b9c2db0f203186538.jpg

Вернёмся к коду. Объявим ещё одну публичную переменную. Она будет отвечать за время в секундах, через которое произойдёт создание нового крипа. Также объявим приватную переменную timer.
public float spawnTime = 1f;
private float timer = 0;

С каждым кадром переменная timer будет уменьшать своё значение на дельту времени, пока не достигнет нуля или отрицательного значения. После чего, она примет значение переменной spawnTime и создаст нового крипа на сцене. И всё начнётся по новой.
Реализуем вышесказанное в методе Update:
timer -= Time.deltaTime;

if (timer <= 0)
{
   Instantiate(spawnObject, transform.position, transform.rotation);
   timer = spawnTime;
}

Функция Instantiate создаёт копию объекта и возвращает на него ссылку. В данной перегрузке принимает аргументы: ссылка на оригинальный объект, позиция и вращение для вставки нового объекта.

Весь код скрипта Spawner будет выглядеть так:

using UnityEngine;

public class Spawner : MonoBehaviour
{
   public GameObject spawnObject;
   public float spawnTime = 1f;

   private float timer = 0;

   void Start()
   {
   }
   
   void Update()
   {
      timer -= Time.deltaTime;

      if (timer <= 0)
      {
         Instantiate(spawnObject, transform.position, transform.rotation);
         timer = spawnTime;
      }
   }
}

Крипы (противники)


Сохраним проект и перейдём в редактор Unity.
Создадим новый объект сферу. Именно так будут выглядеть крипы в моём уроке. Занулим позицию. Немного уменьшим сферу по всем 3-м осям.
c19e54a3643d4e9c9318ac743fe77527.jpg

В папке материалов создадим новый материал. Назовём его Enemy — «Противник».
47087e179589493c90ec3114cd1e51a2.jpg

Я задам ему красный цвет. Переместим материал на сферу. Теперь создадим новый скрипт для того чтобы вдохнуть в крипа жизнь.

d5145597ccee4c5a867e22715c379e6f.jpg

Переименуем сферу в Enemy и перетащим на неё одноимённый скрипт.
c9f5c073f6b0439bb0b048f268d03e9b.jpg

Любой уважающий себя крип должен двигаться к цели


Переходим к коду. Так как структура кода проекта была изменена в редакторе Unity, нам предлагают перезагрузить проект или выбрать другое действие.
f38db10a86dd4804a079850805cc3e17.jpg

Выберем перезагрузку и откроем скрипт Enemy. Объявим приватные переменные. Первая для хранения объекта содержащий вэйпоинты. Вторая для хранения трансформации текущего вэйпоинта (точки пути).
private Transform waypoints;
private Transform waypoint;

Именно к текущему вэйпоинту крип будет идти, пока собственно не дойдёт. После чего он выберет следующую точку и направится уже к ней. Объявим ещё одну переменную.
private int waypointIndex = -1;

Она будет хранить порядковый номер текущей точки пути. Зададим начальное значение -1. Почему так, узнаете дальше.

В методе Start напишем код для поиска объекта на сцене с именем WayPoints и установки первого вэйпоинта в качестве текущего:

waypoints = GameObject.Find("WayPoints").transform;
NextWaypoint();

Теперь опишем метод для выбора следующей точки пути:
void NextWaypoint()
{
   // Тут был код…
}

В теле метода инкрементируем порядковый номер точки:
waypointIndex++;

Далее, проверяем, больше или равно ли значение индекса от кол-ва точек пути. Если условие верно, то уничтожаем объект на сцене и прерываем выполнение метода.
if (waypointIndex >= waypoints.childCount)
{
   Destroy(gameObject);
   return;
}

После блока if, переменной waypoint нужно присвоить точку пути по указанному порядковому номеру:
waypoint = waypoints.GetChild(waypointIndex);

Добавим публичную переменную скорости движения крипа:
public float speed = 2f;

В теле метода Update, напишем код движения крипа к текущей точке пути:
Vector3 dir = waypoint.transform.position - transform.position;
dir.y = 0;

Первой строчкой мы узнаём направление движения крипа. Второй строчкой обнуляем ось Y, что бы крип не смог стать кротом или бабочкой.
Объявим локальную переменную скорости для того чтобы не пересчитывать скорость по нескольку раз в методе. Перемещение крипа не должно зависеть от фреймрейта.
float _speed = Time.deltaTime * speed;

Смещаем позицию крипа в сторону точки пути, на шаг равный значению скорости. Для этого мы перемножили шаг на локальную переменную скорости:
transform.Translate(dir.normalized * _speed);

Теперь нужно поставить условие. Если длина вектора меньше или равна длине шага, то это сигнал к смене точки пути.
if (dir.magnitude <= _speed)
   NextWaypoint();

В итоге весь код скрипта Enemy должен выглядеть так:
using UnityEngine;

public class Enemy : MonoBehaviour
{
   public float speed = 2f;

   private Transform waypoints;
   private Transform waypoint;
   private int waypointIndex = -1;

   void Start()
   {
      waypoints = GameObject.Find("WayPoints").transform;
      NextWaypoint();
   }
   
   void Update()
   {
      Vector3 dir = waypoint.transform.position - transform.position;
      dir.y = 0;

      float _speed = Time.deltaTime * speed;
      transform.Translate(dir.normalized * _speed);

      if (dir.magnitude <= _speed)
         NextWaypoint();
   }

   void NextWaypoint()
   {
      waypointIndex++;

      if (waypointIndex >= waypoints.childCount)
      {
         Destroy(gameObject);
         return;
      }

      waypoint = waypoints.GetChild(waypointIndex);
   }
}

Последние приготовления


Сохраняем код и возвращаемся к редактору Unity. Скрипту Spawner, который привязан к одноимённому объекту, нужно указать образец для клонирования. Образцом будет префаб Enemy, которого нет… Создадим его, перетащив объект Enemy из окна Иерархии в папку префабов. Оригинал удалим со сцены.
1e80d6259782439886b76f18daa54f8a.jpg

Теперь можно установить образец, присвоив переменной spawnObject префаб крипа.
7db94b76e7594902a6ce0ca061e72751.jpg

Отключим коллизию у объекта Spawner.
7143bf91850c44eda9e4dee073f002eb.jpg

Сохраняемся и смотрим что получилось.

4b8260e54aee40c991dac81d1fb983aa.gif
Свеженькое мясо пошло по конвееру…

Для большей наглядности можно посмотреть видеоурок:

P. S.: Если у вас есть вопросы или пожелания, оставляйте свои комментарии на YouTube под видео.
На хабре я комментарии не читаю.

Многие заметили, что статья и видео похожи на уроки с этого канала. От части это так. Но я позаимствовал только лишь расстановку вэйпоинтов и построение уровня.

Спасибо за внимание! Конец второй части.

Комментарии (0)

© Habrahabr.ru