Как сделать 2D стрельбу в Unity 5 с пулом объектов
В сегодняшнем уроке мы разберем как сделать стрельбу в Unity 2D с использованием пула объектов (Object pool) для реализации этого менее затратно. Для начала имеем: проект с объектом, который будет стрелять, картинку пули. Картинку пули мы вынесем в игру, добавим на неё BoxCollider2D и поставим галочку около Is Trigger для того, чтоб он задевал все объекты, но не останавливался, а так же сохраним её как префаб в папку Resources\Prefub. Для этого нужно из Hierarchy выделить нашу пулю и перенести её в нужную папку, тогда наша пуля будет выделена синим. Если как-то её поменять после этого, то префаб это не изменит. Нужно будет нажать на кнопку Apply под именем пули. Теперь необходимо реализовать скрипт для полета пули. Создадим скрипт BulletShot в который напишем:
public class BulletShot : MonoBehaviour {
//Скорость нашей пули
public float Speed;
//Время, через которое наша пуля
//уйдет в пул объектов
public float TimeToDisable;
//Каждый раз, когда наша пуля активируется
void OnEnable () {
//Мы будем запускать таймер для того
//Чтоб выключить её
StartCoroutine(SetDisabled(TimeToDisable));
}
IEnumerator SetDisabled(float TimeToDisable)
{
//Данный скрип приостановит свое исполнение на
//TimeToDisable секунд, а потом продолжит работу
yield return new WaitForSeconds(TimeToDisable);
//Выключаем объект, он у нас останется в пуле объектов
//до следующего использования
gameObject.SetActive(false);
}
void Update () {
//Теперь пуля будет лететь вперед до того, пока объект не будет выключен
//Так как наша пуля уже повернута в нужную сторону, а в 2D пространстве
//Вперед это направо, то нашей пуле надо просто лететь направо
//отностительно своего мирового пространства
transform.position = transform.position+transform.right * Speed * Time.deltaTime;
}
private void OnTriggerEnter2D(Collider2D collision)
{
//Тут должна быть ваша обработка попадания
//Вместо этого условия необходимо ваше, которое определит, что
//в Collision находится именно тот объект, который вам нужен
if (collision==null)
{
//Выключаем ожидание выключения чтоб в случае чего не создавать
//несколько копий ожиданий
StopCoroutine("SetDisabled");
//Выключаем объект
gameObject.SetActive(false);
//Дальше весь тот код, который нужнен для вашей игры
}
}
}
Теперь пули должны лететь в нужную сторону, а через некоторое количество секунд отключаться(не забудте выставить секунды и скорость в инспекторе). Но перед тем, как подвести итоги необходимо разобраться с теми частями кода, которые вы не понимаете. Например, IEnumerator, в обычном c# он используется для циклического обращения к элементам коллекции, но в Unity его можно использовать и подругому. Если реализовать метод возвращающий этот интерфейс напрямую в классе, то его можно вызвать как корутину. Это уже специальная вещь сделанная в Unity для того чтоб код выполнялся не слошным потоком, а иногда останавливался. Корутину используют всегда, где необходимо что-то ждать. Например при анимации каста заклинания, или при перезарядке оружия. Теперь вернемся к проекту. Мы подготовили класс BulletShot для запуска его совместно с пулом объектов, но пул объектов еще не готов, как и создание пули. Для этого нам необходимо в класс нашего персонажа (PlayerController), который будет стрелять написать:
public class PlayerController : MonoBehaviour {
//Наш пул объектов, который помогает
//сохранить память при его использовании
//Ведь активировать объект гораздо проще,
//чем его опять создавать
public List ObjectPool;
private void Start()
{
//Создаем новый список, так как List -
//ссылка на динамический массив
ObjectPool = new List();
}
void Update () {
//Выстрел будет производится при клике мышкой
if (Input.GetMouseButtonUp(0) == true)
{
//diff - будет смещением нашего нажатия от объекта
Vector3 diff = Camera.main.ScreenToWorldPoint(Input.mousePosition) - transform.position;
//номализация приводит каждое значение в промежуток
//от -1 до 1
diff.Normalize();
//по нормализованному виду мы находим угол, так как в diff
//находится вектор, который можно перенести на тригонометрическую окружность
float rot_z = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg;
//и приваиваем наш угол персонажу
transform.rotation = Quaternion.Euler(0f, 0f, rot_z);
//Показывает, нашли ли мы выключенный объект в нашем массиве
bool freeBullet = false;
//Теперь необходимо проверить, есть ли выключенный объект в нашем пуле
for (int i = 0; i < ObjectPool.Count; i++)
{
//Смотрим, активен ли объект в игровом пространстве
if (!ObjectPool[i].activeInHierarchy)
{
//Если объект не активен
//То мы задаем ему все нужные параметры
//Позицию
ObjectPool[i].transform.position = transform.position;
//Поворот
ObjectPool[i].transform.rotation = transform.rotation;
//И опять его включаем
ObjectPool[i].SetActive(true);
//Ставим объект найденным, чтоб опять не создавать лишний
freeBullet = true;
break;
}
}
//если свободный объект не был найден, то нужно создать еще один
if (!freeBullet)
{
//Создаем объект с нужными значениями и заносим его в пул
ObjectPool.Add(Instantiate(Resources.Load("Prefub/Bullet"),transform.position,transform.rotation));
}
}
}
}
В итоге при нажатии мышки по мировому пространству будет создаваться или подгружаться уже созданная пуля и лететь в сторону поворота вашего персонажа. Далее необходимо поиграть со скоростью пули и временем её выключения для того, чтоб это подходило для вашей игры. У меня получилось вот так:

Итак, в итоге этого урока мы реализовали стрельбу для нашего персонажа в Unity 5 с пулом объектов.
