Что такое RayCast в Unity и как можно его использовать?

Что такое RayCast в Unity и как можно его использовать?

RayCast — переводится как «бросить луч», собственно, именно это рейкаст и делает. После броска луч возвращает один объект, с которым пересекся.

Так же существует RaycastAll, который делает то же самое, но возвращает все объекты на пути.

У обоих методов есть несколько параметров, таких как:

  • Origin - Точка начала луча в мировых координатах
  • Direction - Направление луча
  • MaxDistance - Длинна луча
  • LayerMask - Маска объектов которые нужно проверять
  • QueryTriggerInteraction - Нужно ли проверять триггеры
public static bool Raycast(Vector3origin, Vector3direction, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteractionqueryTriggerInteraction = QueryTriggerInteraction.UseGlobal); 

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

Как можно использовать Рейкаст? Примеры

Простая стрельба

Первое, что приходит на ум, это расчёт стрельбы. Мы пускаем луч из дула или, как это часто делают, из центра экрана и проверяем, куда он попадёт. Готово!

using UnityEngine;

public class BallisticShooting : MonoBehaviour
{
    void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Shoot();
        }
    }

    void Shoot()
    {
        Vector3 bulletPosition = transform.position;//позиция для начала луча. центр текущего обьекта
        Vector3 bulletVelocity = transform.forward;//задаем направление
        RaycastHit hit;

        if (Physics.Raycast(bulletPosition, bulletVelocity, out hit, bulletVelocity.magnitude))//бросаем луч и проверяем на столкновения
        {
            //тут можно делать различные проверки обьекта hit
            Debug.Log("Попали в обьект "+hit.transform.name);
        }
        
    }
}

Стрельба с балистикой

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

using UnityEngine;

public class BallisticShooting : MonoBehaviour
{
    public float bulletSpeed = 10f;//скорость пули
    public float bulletDrop = 0.1f;//скорость падения пули
    public int maxIterations = 100; //максимальное число повторений просчетов выстрела

    void Update()
    {
        if (Input.GetButtonDown("Fire1"))
        {
            Shoot();
        }
    }

    void Shoot()
    {
        Vector3 bulletPosition = transform.position;//позиция для начала луча. центр текущего обьекта
        Vector3 bulletVelocity = transform.forward * bulletSpeed;//задаем направление и умножаем на скорость
        RaycastHit hit;

        for (int i = 0; i < maxIterations; i++)
        {
            if (Physics.Raycast(bulletPosition, bulletVelocity, out hit, bulletVelocity.magnitude))//бросаем луч и проверяем на столкновения
            {
                //тут можно делать различные проверки обьекта hit
                Debug.Log("Попали в обьект "+hit.transform.name);
                break;
            }
            
            bulletPosition += bulletVelocity; //меняем позицию для следующего луча
            bulletVelocity += Physics.gravity * bulletDrop;//меняем направление с учетом падения пули
        }
    }
}

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

На каждой итерации создаётся новый луч, который начинается в новой позиции и направлен чуть ниже чем предыдущий. Это направление также меняется на каждой итерации.

Клик по объекту

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

using UnityEngine;

public class ObjectClicker : MonoBehaviour
{
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            if (Physics.Raycast(ray, out hit))
            {
                GameObject clickedObject = hit.transform.gameObject;
                Debug.Log("Пользователь кликнул на объект: " + clickedObject.name);
            }
        }
    }
}

В этом примере при нажатии кнопки мыши (Input.GetMouseButtonDown(0)) создаётся луч (Ray), который идёт от положения курсора на экране к сцене. После этого мы используем Physics.Raycast, чтобы определить, на какой объект попал этот луч, и выводим его название в консоль с помощью Debug.Log.

Прыгать?

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

using UnityEngine;

public class JumpChecker : MonoBehaviour
{
    public float raycastDistance = 1.1f; // Расстояние для проверки земли под ногами

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            bool isGrounded = CheckGrounded();

            if (isGrounded)
            {
                Debug.Log("Персонаж может прыгнуть");
                // Здесь можно добавить код для разрешения прыжка
            }
            else
            {
                Debug.Log("Персонаж не может прыгнуть");
                // Здесь можно добавить код для запрета прыжка
            }
        }
    }

    bool CheckGrounded()
    {
        RaycastHit hit;
        if (Physics.Raycast(transform.position, Vector3.down, out hit, raycastDistance))
        {
            return true; // Персонаж стоит на земле
        }
        else
        {
            return false; // Персонаж не стоит на земле
        }
    }
}

5/5 (1)

Оцените