Как сделать 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 с пулом объектов.