Capítulo 28 Detección de rayos de unidad

En este capítulo presentamos los rayos. Un rayo es lanzar una línea recta desde un punto fijo a una dirección.Durante el proceso de lanzamiento, es necesario juzgar si el rayo choca con el objeto del juego. Los rayos se pueden usar para detectar si el arma está apuntando al objetivo en el juego de disparos; también puede determinar si el mouse está apuntando al objeto del juego. La forma de crear rayos generalmente se implementa mediante código. A continuación, creemos una nueva escena "SampleScene3.unity". Tenga en cuenta aquí que la detección de rayos se basa en el sistema físico, por lo que solo los objetos del juego con componentes de cuerpo de colisión pueden ser detectados por rayos. Afortunadamente, en Unity, el cubo o la esfera creados vienen automáticamente con los componentes del cuerpo de colisión correspondientes.

Creamos tres esferas Sphere1, Sphere2 y Sphere3, y luego lanzamos un rayo desde Sphere1 a la dirección negativa del eje X (el lado izquierdo de la imagen de arriba). Entonces este rayo debería poder detectar Sphere2 y Sphere3.

A continuación, creamos un archivo de script "RayScript.cs" y lo adjuntamos a Sphere1, el contenido es el siguiente.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayScript : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            // 射线的起点(Sphere1的位置)
            Vector3 origin = transform.position;
            // 射线的方向(X轴负方向)
            Vector3 direction = Vector3.left;
            // 射线碰撞的目标对象
            RaycastHit hitInfo;
            // 射线的最大长度
            float maxDistance = 100;

            // 创建射线,返回是否检测到碰撞对象
            bool raycast = Physics.Raycast(origin, direction, out hitInfo, maxDistance);

            // 如果发生碰撞,碰撞信息就被存储到 hitInfo 中
            if (raycast)
            {
                // 获取碰撞点坐标
                Vector3 point = hitInfo.point;
                Debug.Log("碰撞点坐标:" + point);

                // 获取碰撞目标的名称
                string name = hitInfo.collider.name;
                Debug.Log("碰撞对象名称:" + name);

                // 获取目标的碰撞体组件
                Collider coll = hitInfo.collider;

                //获取目标的Transgorm组件
                Transform trans = hitInfo.transform;
            }
        }
    }
}

El código anterior es muy simple, usamos cuatro parámetros para crear un rayo a través del método Physics.Raycast, y luego usamos el tercer parámetro RaycastHit hitInfo para que sea la información del objetivo de colisión que necesitamos. Podemos usar este objeto para obtener la información de posición del punto de colisión entre el rayo y el objetivo, así como el nombre del objeto de juego del objetivo y su componente colisionador o componente de transformación. De hecho, el método Physics.Raycast también tiene un quinto parámetro int layerMask, que se usa para especificar la capa de detección e ignorar otras capas. En nuestro capítulo anterior, mencionamos que la detección de colisiones puede limitarse por capa. Podemos especificar que los objetos del juego entre las capas colisionen, y lo mismo se aplica a la detección de colisión de rayos. No introduciremos este parámetro en detalle aquí.

En el desarrollo de juegos, debido a que los rayos son invisibles, a veces no podemos juzgar la efectividad de la colisión de rayos. En este momento, podemos usar la función Debug.DrawLine() y Debug.DrawRay() para simular rayos. Primero introduzca DrawLine,

Debug.DrawLine(Vector3 start, Vector3 end, Color color=Color.white, float duration=0.0f, bool depthTest=true);

Los parámetros son punto de inicio de la línea, punto final de la línea, color el color de la línea y duración la duración de la línea.

prueba de profundidad Si la línea está ocluida por objetos cercanos a la cámara.

Debug.DrawRay(Vector3 start, Vector3 dir, Color color=Color.white, float duration=0.0f, bool depthTest=true);

Los parámetros son el punto de inicio del rayo de inicio, la dirección y la longitud del rayo de dirección, el color del rayo de color, la duración del rayo de duración y la profundidad. Prueba si la cámara está bloqueada por un objeto cercano a la cámara.

A continuación, usamos el método Debug.DrawRay para simular la cámara en el caso del código anterior y agregamos el siguiente código

// 画一条蓝线来模拟射线
Debug.DrawRay(origin, direction * 100, Color.blue, 100);

A continuación, reiniciamos el proyecto Play y luego presionamos la tecla A para volver a la vista Escena (no a la vista Juego) para ver.

Ahora podemos ver un rayo azul simulado emitido por Sphere1.

De la figura anterior, podemos ver que el rayo no solo pasó a través de la bola amarilla Sphere2, sino que también pasó a través de la bola verde Sphere3. ¿Cómo puedo conseguir la Sphere3 verde? Esto requiere la ayuda de la función Physics.RaycastAll. Esta función es similar a la función Physics.Raycast, pero el resultado devuelto es diferente. El valor de retorno de esta función es una matriz de RaycastHit. A continuación, modifiquemos el código nuevamente, de la siguiente manera

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            // 射线的起点(Sphere1的位置)
            Vector3 origin = transform.position;
            // 射线的方向(X轴负方向)
            Vector3 direction = Vector3.left;
            // 射线碰撞的目标对象
            //RaycastHit hitInfo;
            // 射线的最大长度
            float maxDistance = 100;

            // 创建射线,返回是否检测到碰撞对象
            //bool raycast = Physics.Raycast(origin, direction, out hitInfo, maxDistance);
            RaycastHit[] hitInfos = Physics.RaycastAll(origin, direction, maxDistance);

            // 如果发生碰撞,碰撞信息就被存储到 hitInfo 中
            //if (raycast)
            foreach(RaycastHit hitInfo in hitInfos)
            {
                // 获取碰撞点坐标
                Vector3 point = hitInfo.point;
                Debug.Log("碰撞点坐标:" + point);

                // 获取碰撞目标的名称
                string name = hitInfo.collider.name;
                Debug.Log("碰撞对象名称:" + name);

                // 获取目标的碰撞体组件
                Collider coll = hitInfo.collider;

                //获取目标的Transgorm组件
                Transform trans = hitInfo.transform;
            }

            // 画一条蓝线来模拟射线
            Debug.DrawRay(origin, direction * 100, Color.blue, 100);
        }
    }

Reproduzcamos el proyecto, la captura de pantalla de la salida de la consola es la siguiente

En el desarrollo real de juegos, a veces necesitamos detectar si ocurre una colisión dentro de un cierto rango. Por ejemplo, queremos detectar si hay algunos objetos del juego en un radio de 100 metros y, si existen, los atacaremos activamente. En este punto, no podemos cumplir con tal requisito usando un solo rayo. Unity nos proporciona una gran cantidad de formas diferentes de detección de rayos. Aquí, podemos usar Physics.OverlapSphere para la detección de colisiones de esferas o Physics.OverlapBox para la detección de cubos. Devuelven una matriz Collider[], por ejemplo, usamos rayos para detectar todos los objetos dentro de los 100 metros cercanos

Collider[] colisionadores = Physics.OverlapSphere(transform.postion, 100.0f);

foreach(Colisionador colisionador en colisionadores){ …… }

Finalmente, presentemos otra forma de usar la cámara, que es hacer clic con el mouse para seleccionar el objeto del juego en la escena. Su principio es muy simple, es lanzar un rayo desde la posición de la cámara hasta la posición del clic del mouse y luego realizar la detección de colisión. A continuación, creemos un script "RayClickScript.cs" y adjúntelo a la cámara.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayClickScript : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        // 鼠标左键按下
        if (Input.GetMouseButtonDown(0))
        {
            // 从相机位置发射一条射线经过屏幕上的鼠标点击位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // 声明一个射线碰撞信息类
            RaycastHit hit;

            // 进行碰撞检测
            bool res = Physics.Raycast(ray, out hit);

            // 如果产生了碰撞
            if(res){
                Debug.Log("碰撞点:" + hit.point);
                Debug.Log("碰撞目标:" + hit.transform.name);
            }
        }
    }
}

Luego jugamos el proyecto, usa el mouse para hacer clic en la bola verde Sphere3,

A continuación, hagamos algo interesante. Hacemos clic en un punto del plano Plane y luego dejamos que la bola verde Sphere3 se mueva hasta ese punto. ¿Cómo lograr esta cosa interesante? Los cambios de código son los siguientes

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class RayClickScript : MonoBehaviour
{
    // 绿球Sphere3
    private GameObject sphere3;

    // 是否移动
    private bool isMove = false;

    // 目标点
    private Vector3 target = Vector3.zero;

    // Start is called before the first frame update
    void Start()
    {
        // 获取绿球Sphere3
        sphere3 = GameObject.Find("Sphere3");
    }

    // Update is called once per frame
    void Update()
    {
        // 鼠标左键按下
        if (Input.GetMouseButtonDown(0))
        {
            // 从相机位置发射一条射线经过屏幕上的鼠标点击位置
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

            // 声明一个射线碰撞信息类
            RaycastHit hit;

            // 进行碰撞检测
            bool res = Physics.Raycast(ray, out hit);

            // 如果产生了碰撞
            if (res && hit.transform.name == "Plane")
            {
                // 目标点(Y轴上保持不变)
                isMove = true;
                target = new Vector3(hit.point.x, sphere3.transform.position.y, hit.point.z);
                //Debug.Log("碰撞点:" + hit.point);
                //Debug.Log("碰撞目标:" + hit.transform.name);
            }
        }

        // 如果发生碰撞就让绿球移动到目标点
        if (isMove)
        {
            // 绿球朝向目标点
            sphere3.transform.LookAt(target);

            // 角色移动到目标点的距离
            float distance = Vector3.Distance(target, sphere3.transform.position);

            // 没有到达目标点就一直移动下去
            if (distance > 0.1f)
            {
                // 旋转后向前移动即可
                sphere3.transform.Translate(transform.forward * 0.2f);
            }
            else
            {
                // 移动结束
                isMove = false;
            }
        }
    }
}

No explicaremos el código anterior, solo reprodúzcalo y ejecútelo para ver el efecto.

El contenido de este curso se ha compartido con Baidu Netdisk: https://pan.baidu.com/s/1e1jClK3MnN66GlxBmqoJWA?pwd=b2id

Supongo que te gusta

Origin blog.csdn.net/konkon2012/article/details/130479844
Recomendado
Clasificación