le mie informazioni di contatto
Posta[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Il rilevamento dei raggi, secondo il nome, utilizza un raggio per rilevare se colpisce uno o più oggetti
L’esame radiografico è composto da due parti: RaggiERilevamento
I raggi possono essere visti in molti luoghi della vita quotidiana, come ad esempiotorcia elettrica,Penna per girare pagine laser ppt, a metà degli anni QingyuCiclope
Un raggio è costituito da un punto iniziale, una direzione e una distanza, vale a dire: origin
, direction
Edistance
In fisica, la distanza del raggio è infinita, quindi il raggio fisico ha solo un punto iniziale e una direzione. Nel gioco, anche la distanza massima del raggio è limitata dal sistema. Generalmente, personalizziamo la distanza, ad esempio 1000,0 metri Quella che segue è una descrizione di Ray.
In Unity, Ray è una struttura I membri di base della struttura del volume includonoorigin
, direction
EGetPoint
Cioè, il punto iniziale, la direzione e la posizione di un punto ad una certa distanza lungo il raggio. Quello che segue è il codice per Ray in 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);
}
}
Secondo il codice sopra, si può vedere che un raggio può essere costruito direttamente utilizzando il costruttore Ray, ad esempio:
Ray ray = new Ray(Vector3.zero, Vector3.forward); // 射线的起点 + 射线的方向
Secondo il codice precedente, possiamo vedere che il punto iniziale del raggio è l'origine delle coordinate globali in Unità (0,0,0) e la direzione del raggio è la direzione in avanti delle coordinate globali.
In realtà, il nostro puntatore laser e la torcia possono essere visti, ma i raggi in Unity sono invisibili. Pertanto, se vogliamo visualizzare i raggi, possiamo utilizzare i seguenti metodi:
Debug.DrawRay()
raggio di visualizzazioneLineRenderer
Il componente disegna il raggioCostruire o visualizzare semplicemente i raggi non ha significato. Equivale a tenere uno strumento in mano e lavorare senza lo strumento.
Come utilizzare i raggi per il rilevamento di oggetti.
Pensateci attentamente: nella nostra vita quotidiana, i nostri puntatori laser o torce possono visualizzare punti luminosi sul muro o illuminare un determinato luogo dopo l'emissione di luce laser. Ciò dimostra che è possibile interagire con il muro, in altre parole, che il raggio si scontra l'oggetto/L'oggetto è stato rilevato Utilizzare la seguente API in Unity per determinare se l'oggetto è stato rilevato.
// 基础版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);
Per utilizzare il rilevamento dei raggi, è necessario utilizzare il filePhysics
Libreria, che contiene funzioni statiche legate alla fisica
Vedendo le funzioni sovraccaricate di cui sopra, spesso non sappiamo quale utilizzare, infatti, abbiamo solo bisogno di quelle di base. Per quelli con molti parametri, in realtà utilizziamo diversi parametri sovraccaricati a seconda delle esigenze.
Per prima cosa guarda la versione base dell'API public static bool Raycast(Ray ray);
In base al valore restituito, quello che possiamo sapere è se il raggio colpisce un oggetto. Se colpisce, restituisce true. In caso contrario, restituisce false.
Rilevamento dei raggi in un'altra APIpublic static bool Raycast(Ray ray, out RaycastHit hitInfo);
C'è un altro parametro inhitInfo
Il parametro hitInfo è la struttura informativa dell'oggetto colpito dal raggio. La struttura è relativamente grande, il che significa che contiene più informazioni. È uguale al risultato dell'oggetto colpito dal rilevamento del raggio in Unreal Engine (.FHitResult
) sono simili Da una prospettiva macro o da una prospettiva pratica, quando un raggio colpisce un oggetto, possiamo ottenere informazioni sull'oggetto stesso e informazioni sul punto colpito.
Ottenere le informazioni di un oggetto è di facile comprensione: come il nome dell'oggetto, la componente di trasformazione dell'oggetto, il Tag dell'oggetto...
Ottenere l'informazione dell'hit point, cioè l'informazione di un punto (hit point) in cui il raggio colpisce l'oggetto: come ad esempio le coordinate del punto,Normale(normale), piano normale, il punto dicolore del vertice…
Quello che segue èRaycastHit
Informazioni sulla struttura, quelle di uso comune hanno commenti aggiunti. Ce ne sono anche molte di uso comune senza commenti aggiunti, ad esempiolightmapCoord
Sono coordinate della mappa luminosa, utilizzate per il rendering.
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; }
}
}
Vale a direHitInfo
Salva le informazioni sull'oggetto che colpiamo, possiamo usare queste informazioni per fare più cose
Nell'Unità,layerMask
È un meccanismo di selezione del livello di oggetto utilizzato per controllare la collisione fisica, il ray casting, il rilevamento dei raggi e altre operazioni.IMPOSTANDOlayerMask
, è possibile specificare quali layer includere o escludere da queste operazioni.
Torna all'API di rilevamento dei raggi comunemente utilizzata public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
mezzo.
Nell'API precedente, è ovvio che maxDistance è la distanza del raggio. Anche il sistema ha un valore massimo impostato suMathf.Infinity
C'è anche un parametro layerMask in questa API, che è la maschera di livello.
Per distinguere gli oggetti di gioco in Unity, possiamo distinguere gli oggetti di gioco aggiungendo tag, ovvero aggiungendo tag. Tuttavia, i tag sono più problematici. Dobbiamo inserire manualmente il nome del tag ed è facile commettere errori durante la digitazione. Allo stesso tempo, poiché si tratta di una stringa, la velocità di calcolo nella parte inferiore di Unity è leggermente più lenta. In Unity esiste un concetto di livello.
La layerMask in Unity contiene 32 livelli, alcuni dei quali sono già utilizzati dal sistema, come ad esempioPlayer
strato, UI
Livelli. Esistono ancora molti livelli che non vengono utilizzati dal sistema. Possiamo aggiungere livelli e quindi classificarli aggiungendo livelli di lavoro minorile agli oggetti del gioco.
Come aggiungere un livello? È necessario fare clic su Livello nel pannello Ispettore di qualsiasi oggetto, quindi fare clicAggiungi livelloQuesto è tutto, quindi specifica manualmente il livello per gli oggetti che devono essere modificati.
Come usarlo dopo aver aggiunto manualmente il livello.
esisterepublic static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
mezzolayereMask
Abbiamo imparato che fa aint
Tipo di numero intero, tuttavia, non possiamo inserire direttamente i numeri, le regole di riempimento utilizzano operazioni di spostamento,
Come compilare layerMask:
Ottieni il valore della maschera di livello:
1 << LayerMask.NameToLayer("LayerName")
. Ciò restituisce un valore intero che rappresenta la layerMask per questo livello.Combina più strati:
|
. Per esempio,layerMask = LayerMask.GetMask("Layer1", "Layer2")
Verrà creata una maschera di livello, incluso "Layer1" e "Layer2".escludere il livello:
^
per escludere livelli specifici. Per esempio,layerMask = ~LayerMask.GetMask("ExcludeLayer")
。Controlla il livello:
layerMask.value & (1 << gameObject.layer)
. Se il risultato non è 0, significa che l'oggetto è in 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))
{
// 处理射线击中的对象
}
Quello che segue è il codice che utilizza il parametro hitInfo senza e con il parametro 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);
}
}
}
Utilizzare il rilevamento del raggio per implementare un puntatore laser rotante Quando si incontra un oggetto, la lunghezza del raggio viene ridotta ed è necessario tracciare il raggio.
Competenze richieste: Rilevamento raggi + Rotazione + LineRender
Quello che segue è il codice
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));
}
}
}
Codice ottimizzato
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));
}
}
I rendering sono i seguenti
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);
}
}
}
}