minhas informações de contato
Correspondência[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
A detecção de raio, de acordo com o nome, usa um raio para detectar se ele atinge um objeto/múltiplos objetos
O teste radiográfico consiste em duas partes: RaioseDetecção
Os raios podem ser vistos em muitos lugares da vida diária, comolanterna,caneta para virar página a laser ppt, no meio dos anos QingyuCiclope
Um raio consiste em um ponto inicial, uma direção e uma distância, a saber: origin
, direction
edistance
Na física, a distância de um raio é infinita, então um raio físico tem apenas um ponto de partida e uma direção. No jogo, a distância máxima do raio também é limitada pelo sistema. Geralmente, personalizamos a distância, como. 1000,0 metros. A seguir está uma descrição de Ray.
No Unity, Ray é uma estrutura. Os membros básicos do volume da estrutura incluem.origin
, direction
eGetPoint
. Ou seja, o ponto inicial, a direção e a posição de um ponto a uma certa distância ao longo do raio A seguir está o código para Ray no 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);
}
}
De acordo com o código acima, pode-se observar que um raio pode ser construído diretamente usando o construtor Ray, por exemplo:
Ray ray = new Ray(Vector3.zero, Vector3.forward); // 射线的起点 + 射线的方向
De acordo com o código acima, podemos ver que o ponto inicial do raio é a origem das coordenadas mundiais na Unidade (0,0,0), e a direção do raio é a direção direta das coordenadas mundiais.
Na realidade, nosso ponteiro laser e lanterna podem ser vistos, mas os raios no Unity são invisíveis. Portanto, se quisermos exibir os raios, os métodos que podemos usar são:
Debug.DrawRay()
raio de exibiçãoLineRenderer
O componente desenha o raioApenas construir ou exibir os raios não tem sentido. É equivalente a segurar uma ferramenta na mão e trabalhar sem a ferramenta.
Como usar raios para detecção de objetos.
Pense bem: em nosso dia a dia, nossos ponteiros laser ou lanternas podem exibir pontos de luz na parede ou iluminar um determinado local após emitirem luz laser. Isso mostra que é possível interagir com a parede, ou seja, o raio colide com ela. o objeto/O objeto é detectado Use a seguinte API no Unity para determinar se o objeto foi detectado.
// 基础版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 usar a detecção de raios, você precisa usar oPhysics
Biblioteca, que contém funções estáticas relacionadas à física
Vendo as funções sobrecarregadas acima, muitas vezes não sabemos qual usar. Na verdade, precisamos apenas das funções básicas. Para aquelas com muitos parâmetros, usamos diferentes parâmetros sobrecarregados de acordo com as necessidades.
Primeiro, dê uma olhada na versão básica da API public static bool Raycast(Ray ray);
De acordo com o valor de retorno, o que podemos saber é se o raio atinge um objeto. Se atingir, retorna verdadeiro. Caso contrário, retorna falso.
Detecção de raio em outra APIpublic static bool Raycast(Ray ray, out RaycastHit hitInfo);
Há mais um parâmetro emhitInfo
O parâmetro hitInfo é a estrutura de informação do objeto atingido pelo raio. A estrutura é relativamente grande, o que significa que contém mais informações que o resultado do objeto atingido pela detecção do raio no Unreal Engine (.FHitResult
) são semelhantes de uma perspectiva macro ou de uma perspectiva prática, quando um raio atinge um objeto, podemos obter informações sobre o próprio objeto e as informações sobre o ponto de impacto.
Obter as informações de um objeto é fácil de entender: como o nome do objeto, o componente transfrom do objeto, o Tag do objeto...
Obtenha as informações do ponto de acerto, ou seja, as informações de um ponto (ponto de acerto) onde o raio atinge o objeto: como as coordenadas do ponto,Normal(normal), plano normal, o ponto decor do vértice…
A seguirRaycastHit
Informações de estrutura, as comumente usadas adicionaram comentários. Também existem muitas comumente usadas sem comentários adicionados, como.lightmapCoord
São coordenadas claras do mapa, usadas para renderização.
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; }
}
}
Isso quer dizerHitInfo
Salva as informações sobre o objeto que atingimos, podemos usar essas informações para fazer mais coisas
Na Unidade,layerMask
É um mecanismo de seleção de camada de objeto usado para controlar colisão física, projeção de raios, detecção de raios e outras operações.definindolayerMask
, você pode especificar quais camadas devem ser incluídas ou excluídas dessas operações.
Volte para a API de detecção de raios comumente usada public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
meio.
Na API acima, nem é preciso dizer que maxDistance é a distância do raio. O sistema também tem um valor máximo definido como.Mathf.Infinity
. Também existe um parâmetro layerMask nesta API, que é a máscara de camada.
Para distinguir os objetos do jogo no Unity, podemos distinguir os objetos do jogo adicionando tags, ou seja, adicionando Tags. No entanto, as tags são mais problemáticas. Precisamos inserir manualmente o nome da tag e é fácil cometer erros ao digitar manualmente. Ao mesmo tempo, por ser uma string, a velocidade é um pouco mais lenta no cálculo na parte inferior do Unity. Existe um conceito de camadas no Unity.
A layerMask no Unity contém 32 camadas, algumas das quais já utilizadas pelo sistema, comoPlayer
camada, UI
Camadas. Ainda existem muitas camadas que não são utilizadas pelo sistema. Podemos adicionar camadas e depois classificá-las adicionando camadas de trabalho infantil aos objetos do jogo.
Como adicionar uma camada? Você precisa clicar em Camada no painel Inspetor de qualquer objeto e clicar emAdicionar camadaÉ isso, depois especifique manualmente a camada dos objetos que precisam ser modificados.
Como usá-lo após adicionar a camada manualmente.
existirpublic static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
meiolayereMask
Aprendemos que isso faz umint
Tipo de inteiro, porém, não podemos preencher os números diretamente, as regras de preenchimento utilizam operações de deslocamento,
Como preencher camadaMask:
Obtenha o valor da máscara de camada:
1 << LayerMask.NameToLayer("LayerName")
. Isso retorna um valor inteiro que representa o layerMask para esta camada.Combine várias camadas:
|
. Por exemplo,layerMask = LayerMask.GetMask("Layer1", "Layer2")
Uma camadaMask será criada, incluindo "Layer1" e "Layer2".excluir camada:
^
para excluir camadas específicas. Por exemplo,layerMask = ~LayerMask.GetMask("ExcludeLayer")
。Verifique a camada:
layerMask.value & (1 << gameObject.layer)
. Se o resultado não for 0, significa que o objeto está em 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))
{
// 处理射线击中的对象
}
A seguir está o código que usa o parâmetro hitInfo sem e com o 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);
}
}
}
Use a detecção de raio para implementar um ponteiro laser giratório. Ao encontrar um objeto, o comprimento do raio é reduzido e o raio precisa ser desenhado.
Habilidades necessárias: Detecção de Raios + Rotação + LineRender
O seguinte é o 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 otimizado
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));
}
}
As renderizações são as seguintes
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);
}
}
}
}