Mi informacion de contacto
Correo[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
La detección de rayos, según su nombre, utiliza un rayo para detectar si golpea un objeto o varios objetos.
Las pruebas radiográficas constan de dos partes: rayosyDetección
Los rayos se pueden ver en muchos lugares de la vida diaria, comoLinterna,lápiz láser ppt para pasar páginas, en medio de los años de QingyuCíclope
Un rayo consta de un punto de partida, una dirección y una distancia, a saber: origin
, direction
ydistance
En física, la distancia del rayo es infinita, por lo que el rayo físico tiene solo un punto de partida y una dirección. En el juego, la distancia máxima del rayo también está limitada por el sistema. Generalmente, personalizamos la distancia, por ejemplo. 1000,0 metros La siguiente es una descripción de Ray.
En Unity, Ray es una estructura. Los miembros básicos del volumen de la estructura incluyen.origin
, direction
yGetPoint
Es decir, el punto de partida, la dirección y la posición de un punto a cierta distancia a lo largo del rayo. El siguiente es el código de Ray en Unity.
using System;
namespace UnityEngine
{
public struct Ray : IFormattable
{
public Ray(Vector3 origin, Vector3 direction);
public Vector3 origin { get; set; } // 起点(向量)
public Vector3 direction { get; set; }// 方向(向量)
public Vector3 GetPoint(float distance);// 沿着射线一定距离的点(向量)
public override string ToString();
public string ToString(string format);
public string ToString(string format, IFormatProvider formatProvider);
}
}
Según el código anterior, se puede ver que un rayo se puede construir directamente usando el constructor Ray, por ejemplo:
Ray ray = new Ray(Vector3.zero, Vector3.forward); // 射线的起点 + 射线的方向
Según el código anterior, podemos ver que el punto inicial del rayo es el origen de las coordenadas mundiales en Unity (0,0,0), y la dirección del rayo es la dirección directa de las coordenadas mundiales.
En realidad, nuestro puntero láser y nuestra linterna se pueden ver, pero los rayos en Unity son invisibles. Por lo tanto, si queremos mostrar los rayos, podemos usar los siguientes métodos:
Debug.DrawRay()
rayo de visualizaciónLineRenderer
El componente dibuja el rayo.Simplemente construir o mostrar los rayos no tiene significado. Es equivalente a sostener una herramienta en la mano y trabajar sin ella.
Cómo utilizar rayos para la detección de objetos.
Piénselo detenidamente: en nuestra vida diaria, nuestros punteros láser o linternas pueden mostrar puntos de luz en la pared o iluminar un lugar determinado después de emitir luz láser. Esto muestra que se puede interactuar con la pared, en otras palabras, el rayo choca. el objeto/ El objeto se detecta. Utilice la siguiente API en Unity para determinar si se detecta el objeto.
// 基础版API
public static bool Raycast(Ray ray);
public static bool Raycast(Vector3 origin, Vector3 direction, float maxDistance, int layerMask);
public static bool Raycast(Ray ray, out RaycastHit hitInfo);
public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance);
// 常用版API
public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
public static bool Raycast(Ray ray, float maxDistance);
Para utilizar la detección de rayos, debe utilizar elPhysics
Biblioteca, que contiene funciones estáticas relacionadas con la física.
Al ver las funciones sobrecargadas anteriores, a menudo no sabemos cuál usar. De hecho, solo necesitamos las básicas. Para aquellos con muchos parámetros, en realidad usamos diferentes parámetros sobrecargados según las necesidades.
Primer vistazo a la versión básica de la API. public static bool Raycast(Ray ray);
Según el valor de retorno, lo que podemos saber es si el rayo impacta en un objeto. Si impacta, devuelve verdadero. Si no, devuelve falso.
Detección de rayos en otra APIpublic static bool Raycast(Ray ray, out RaycastHit hitInfo);
Hay un parámetro más enhitInfo
El parámetro hitInfo es la estructura de información del objeto alcanzado por el rayo. La estructura es relativamente grande, lo que significa que contiene más información. Es el mismo que el resultado del objeto alcanzado por la detección de rayos en Unreal Engine (.FHitResult
) son similares desde una perspectiva macro o desde una perspectiva práctica, cuando un rayo golpea un objeto, podemos obtener información sobre el objeto en sí y la información sobre el punto de impacto.
Obtener la información de un objeto es fácil de entender: como el nombre del objeto, el componente transfrom del objeto, la etiqueta del objeto...
Obtenga la información del punto de impacto, es decir, la información de un punto (punto de impacto) donde el rayo impacta el objeto: como las coordenadas del punto,Normal(normal), plano normal, el punto decolor del vértice…
Lo siguiente esRaycastHit
Información de estructura, las de uso común tienen comentarios agregados. También hay muchas de uso común sin comentarios agregados, como.lightmapCoord
Son coordenadas de mapa ligeras que se utilizan para renderizar.
namespace UnityEngine
{
public struct RaycastHit
{
public Collider collider { get; } // 碰撞器
public int colliderInstanceID { get; }
public Vector3 point { get; set; } // 击中的点(命中点)
public Vector3 normal { get; set; } // 命中点的法线
public Vector3 barycentricCoordinate { get; set; } // 重心坐标
public float distance { get; set; } // 命中点距离射线起点的距离
public int triangleIndex { get; }
public Vector2 textureCoord { get; }
public Vector2 textureCoord2 { get; }
public Transform transform { get; } // Transform组件
public Rigidbody rigidbody { get; } // 刚体组件
public ArticulationBody articulationBody { get; }
public Vector2 lightmapCoord { get; }
public Vector2 textureCoord1 { get; }
}
}
Es decirHitInfo
Guarda la información sobre el objeto que golpeamos, podemos usar esta información para hacer más cosas
En unidad,layerMask
Es un mecanismo de selección de capas de objetos que se utiliza para controlar la colisión física, la proyección de rayos, la detección de rayos y otras operaciones.configurandolayerMask
, puede especificar qué capas deben incluirse o excluirse de estas operaciones.
Continúe hasta la API de detección de rayos más utilizada public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
medio.
En la API anterior, no hace falta decir que maxDistance es la distancia del rayo. El sistema también tiene un valor máximo establecido en.Mathf.Infinity
También hay un parámetro LayerMask en esta API, que es la máscara de capa.
Para distinguir los objetos del juego en Unity, podemos distinguir los objetos del juego agregando etiquetas, es decir, agregando etiquetas. Sin embargo, las etiquetas son más problemáticas. Necesitamos ingresar manualmente el nombre de la etiqueta y es fácil cometer errores al escribir a mano. Al mismo tiempo, debido a que es una cadena, la velocidad de cálculo en la parte inferior de Unity es un poco más lenta. Existe un concepto de capa en Unity.
LayerMask en Unity contiene 32 capas, algunas de las cuales ya son utilizadas por el sistema, comoPlayer
capa, UI
Capas. Todavía hay muchas capas que el sistema no utiliza. Podemos agregar capas y luego clasificarlas agregando capas de trabajo infantil a los objetos del juego.
¿Cómo agregar una capa? Debe hacer clic en Capa en el panel Inspector de cualquier objeto y luego hacer clic.Agregar capaEso es todo, luego especifique manualmente la capa para los objetos que deben modificarse.
Cómo usarlo después de agregar la capa manualmente.
existirpublic static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
mediolayereMask
Aprendimos que hace unint
Tipo de número entero, sin embargo, no podemos completar los números directamente, las reglas de llenado usan operaciones de desplazamiento,
Cómo rellenar la máscara de capa:
Obtener el valor de máscara de capa:
1 << LayerMask.NameToLayer("LayerName")
. Esto devuelve un valor entero que representa la máscara de capa para esta capa.Combina varias capas:
|
. Por ejemplo,layerMask = LayerMask.GetMask("Layer1", "Layer2")
Se creará una máscara de capa, que incluye "Capa1" y "Capa2".excluir capa:
^
para excluir capas específicas. Por ejemplo,layerMask = ~LayerMask.GetMask("ExcludeLayer")
。Comprobar capa:
layerMask.value & (1 << gameObject.layer)
. Si el resultado no es 0, significa que el objeto está en LayerMask.// 示例代码
// 创建一个包含Layer1和Layer2的layerMask
int layerMask = LayerMask.GetMask("Layer1", "Layer2");
// 排除Layer3
layerMask = ~LayerMask.GetMask("Layer3");
// 使用layerMask进行射线检测
RaycastHit hit;
if (Physics.Raycast(ray, out hit, maxDistance, layerMask))
{
// 处理射线击中的对象
}
El siguiente es el código que utiliza el parámetro hitInfo sin y con el parámetro hitInfo:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RayCast : MonoBehaviour
{
/
// 构建一条射线 : 射线产生的起始点 + 射线的方向.
private Ray ray1 = new Ray(Vector3.zero, Vector3.forward);
// 射线距离
private float rayDistance = 100.0f;
// 击中的判定结果
bool hitResult = false;
// 射线击中的物体
private RaycastHit hitInfo;
void Start()
{
// 不含有hitInfo的函数
bool result1 = Physics.Raycast(Vector3.zero + new Vector3(0,0,10), Vector3.forward, 1000.0f, 1 << LayerMask.NameToLayer("Default"), QueryTriggerInteraction.UseGlobal);
if (result1)
{
Debug.Log("射线击中物体");
}
// 含有hitInfo的函数
hitResult = Physics.Raycast(ray1, out hitInfo, rayDistance, 1 << LayerMask.NameToLayer("Default"), QueryTriggerInteraction.UseGlobal);
if (hitResult == true)
{
print(hitInfo.collider.name);
print(hitInfo.transform);
print(hitInfo.point);
}
}
}
Utilice la detección de rayos para implementar un puntero láser giratorio. Cuando se encuentra con un objeto, la longitud del rayo se reduce y es necesario dibujar el rayo.
Habilidades requeridas: Detección de rayos + Rotación + LineRender
El siguiente es el código
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class RotateRay : MonoBehaviour
{
// LinerRender组件
private LineRenderer lineRenderer = null;
// 构建一条射线 : 射线产生的起始点 + 射线的方向.
private Ray ray = new Ray(Vector3.zero, Vector3.forward);
// 射线距离
private float rayDistance = 1000.0f;
// 击中的判定结果
bool hitResult = false;
// 射线击中的物体
private RaycastHit hitInfo;
void Start()
{
// 添加线条绘制组件
lineRenderer = this.gameObject.AddComponent<LineRenderer>();
InitLineRenderer(lineRenderer);
// 设置射线的起点和方向
ray.origin = this.transform.position;
ray.direction = this.transform.forward;
}
// Update is called once per frame
void Update()
{
// 重新设置射线的位置
ray.origin = this.transform.position;
ray.direction = this.transform.forward;
// 旋转游戏对象 -- 每秒旋转60°
Quaternion quaternion = Quaternion.AngleAxis(60f * Time.deltaTime, this.transform.up);
this.transform.rotation *= quaternion;
// 判断击中的物体
hitResult = Physics.Raycast(ray, out hitInfo, rayDistance, 1 << LayerMask.NameToLayer("Default"), QueryTriggerInteraction.UseGlobal);
if (hitResult == true)
{
print(hitInfo.collider.name);
}
// 显示并更新射线
UpdateLineRendererByRay(lineRenderer, ray, hitResult,hitInfo, rayDistance);
}
/// <summary>
/// 初始化线条渲染组件
/// </summary>
void InitLineRenderer(LineRenderer lineRenderer)
{
// lineRenderer = this.gameObject.AddComponent<LineRenderer>();
lineRenderer.positionCount = 2;
lineRenderer.startWidth = 0.2f;
lineRenderer.endWidth = 0.2f;
lineRenderer.startColor = Color.red;
lineRenderer.endColor = Color.green;
}
/// <summary>
/// 击中物体的时候修改射线的长度
/// </summary>
/// <param name="lineRenderer">lineRenderer组件</param>
/// <param name="ray">射线</param>
/// <param name="hitResult">是否命中物体</param>
/// <param name="hitInfo">命中物体信息</param>
/// <param name="rayDistance">射线距离</param>
void UpdateLineRendererByRay(LineRenderer lineRenderer,Ray ray, bool hitResult, RaycastHit hitInfo, float rayDistance)
{
if (lineRenderer == null || lineRenderer.positionCount < 2)
{
Debug.Log("LineRender组件不可以使用");
return;
}
// 修改起点位置
lineRenderer.SetPosition(0, ray.origin);
// 修改终点位置
if (hitResult == true)
{
lineRenderer.SetPosition(1, hitInfo.point);
}
else
{
lineRenderer.SetPosition(1, ray.GetPoint(rayDistance));
}
}
}
Código optimizado
using UnityEngine;
public class RotateRay : MonoBehaviour
{
private LineRenderer lineRenderer;
private Ray ray;
private float rayDistance = 1000.0f;
private RaycastHit hitInfo;
void Start()
{
lineRenderer = this.gameObject.AddComponent<LineRenderer>();
InitLineRenderer(lineRenderer);
ray = new Ray(Vector3.zero, Vector3.forward);
}
void Update()
{
UpdateRayPosition();
RotateObject();
PerformRaycast();
UpdateLineRenderer();
}
void InitLineRenderer(LineRenderer lineRenderer)
{
lineRenderer.positionCount = 2;
lineRenderer.startWidth = 0.2f;
lineRenderer.endWidth = 0.2f;
lineRenderer.startColor = Color.red;
lineRenderer.endColor = Color.green;
}
void UpdateRayPosition()
{
ray.origin = this.transform.position;
ray.direction = this.transform.forward;
}
void RotateObject()
{
Quaternion rotation = Quaternion.AngleAxis(60f * Time.deltaTime, this.transform.up);
this.transform.rotation *= rotation;
}
void PerformRaycast()
{
int layerMask = 1 << LayerMask.NameToLayer("Default");
hitInfo = new RaycastHit(); // 初始化hitInfo,避免未击中时的错误
Physics.Raycast(ray, out hitInfo, rayDistance, layerMask, QueryTriggerInteraction.UseGlobal);
}
void UpdateLineRenderer()
{
if (lineRenderer == null || lineRenderer.positionCount < 2)
{
Debug.LogError("LineRenderer component is not available or not properly initialized.");
return;
}
lineRenderer.SetPosition(0, ray.origin);
lineRenderer.SetPosition(1, hitInfo.collider != null ? hitInfo.point : ray.GetPoint(rayDistance));
}
}
Las representaciones son las siguientes.
using UnityEngine;
public class CameraRay: MonoBehaviour
{
// 射线距离
private float rayDistance = 1000.0f;
// 特效Prefab--外部可以自定义特效
public GameObject effectPrefab;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
// 从摄像机发出一条射线
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hitInfo;
// 如果射线击中了指定层级的物体
if (Physics.Raycast(ray, out hitInfo, rayDistance, LayerMask.GetMask("Wall")))
{
// 生成特效 --格局法线来计算特效位置
GameObject effectObject = Instantiate(effectPrefab, hitInfo.point, Quaternion.LookRotation(hitInfo.normal));
// 销毁特效,参数为延迟时间
Destroy(effectObject, EffectPrefab.GetComponent<ParticleSystem>().main.duration);
}
}
}
}