Как сделать выстрелы в Unity?

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

Для начала рассмотрим все в теории, а потом уже возьмемся за реализацию и тестирование.

Теория

Физическое тело в виде снаряда

Итак, у нас есть задача бросить камень, надеюсь не в меня) Для этого делается следующее:

  • В момент нажатия на ЛКМ создается объект
  • Мы получает этот объект и толкаем его в нужном направлении
  • Далее движок считает все за нас, мы только смотрим
  • Возможно создаем эффекты приземления

Все просто. Часто именно такой подход и необходим. Так можно симулировать, достаточно медленные снаряды, которые не часто вылетают из оружия. К примеру, снежки, камни, ядра пушек, картофель из пататогана). Проблемы начинаются когда необходимо создать что-то дальнобойные или скорострельное.

При быстром движении такие снаряды могут пролетать сквозь объекты. Способ обхода этого есть, но нагрузка на процессор чуть выше обычного физического тела, а на дальнем расстоянии снаряд все равно особо не видно, так зачем грузить процессор?

Если же нам хочется создать много объектов, проблемы в принципе такие же. Они могут пролетать сквозь объекты, грузить процессор так же скорострельность оружия ограничена размером объекта, так как он будет задевать предыдущий снаряд и они полетят ни так как хотелось бы.

Как же быть? Для таких целей обычно используют рейкаст

Рейкаст для реализации выстрела

В простейшем случае работает это таким образом:

  • Мы выпускаем луч в нужном направлении
  • Определяем куда он попадет
  • рисуем эффект попадания или делаем что то еще

Для расчета падения пули можем провести расчет по скорости и дальности, затем опустив попадание ниже. У такого подхода есть свой минус. Пуля может пролететь сквозь стену если мы ее не просчитаем сами.

Пример как пуля пролетает препятствие
Пример как пуля пролетает препятствие

Как решить данную проблему?

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

Можно запустить симуляцию всего полета "на паузе". Расчет требует времени и соответственно ресурсов, однако точно просчитает полет пули. Это почти так же как и в варианте с физическим объектом, но расчет ведется отдельно от текущего времени и выдается только результат.

Так же выполняется создание обьекта и его пинок в нужном направлении но с игнорированием реального времени.

Либо по школьной физике просчитываем полет тела сами, но зачем? Все равно каждую точку проверять нужно на столкновения.

Практика

Физический снаряд

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

Тестовый стенд
Тестовый стенд

Стрелять будем в точку, без поворота камеры.

using UnityEngine;

public class ShotToClick : MonoBehaviour
{
    public GameObject Bullet;
    public float Power;
    void Update()
    {
        if (Input.GetMouseButtonDown(0)){
            GameObject b = Instantiate(Bullet, transform.position, transform.rotation);
            b.GetComponent<Rigidbody>().AddForce(Vector3.forward * Power, ForceMode.Impulse);
        }
    }
}

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

Первый выстрел
Первый выстрел
Последствия
Последствия

Путь луча

Принцип описан выше, сцена та же самая, код чуть ниже. Для Визуализации я буду создавать "пулю" в точке соприкосновения луча и объекта. В реальном проекте, там нужно оставлять следы от пуль, искры, осколки, все что захотите.

using UnityEngine;

public class ShotToClickRaycast : MonoBehaviour
{
    public GameObject Bullet;//только для визуализации
    public float Power;
    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0)){
             Ray ray =  new Ray(transform.position, transform.forward);
             RaycastHit hit;
                if (Physics.Raycast(ray,out hit)){
                    hit.rigidbody.AddForceAtPosition(ray.direction * Power, hit.point, ForceMode.Impulse);
                    Instantiate(Bullet, hit.point, transform.rotation);
                }
        }
    }
}

При клике мгновенно появляется наш снаряд в месте куда он должен был попасть. Если у нас не большая локация, пуля летит быстро, то можно пренебречь скоростью пули и стрелять прямо так.

Так же можно добавить поведение оружия. Отдача, точность, разброс и тд. Тут уже полностью от ваших хотелок.

Итоги

В данной статье я привел лишь примеры того как можно сделать выстрелы в unity. Надеюсь она вам поможет определиться как действовать дальше и у вас получиться хорошая стрелялка =)

Скачать можно тут.

4.39/5 (9)

Оцените