2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
La détection de rayons, selon son nom, utilise un rayon pour détecter s'il touche un objet/plusieurs objets.
Le test radiographique comprend deux parties : Des rayonsetDétection
Les rayons peuvent être observés à de nombreux endroits de la vie quotidienne, commelampe de poche,stylo tournant la page laser ppt, au milieu des années Qingyucyclope
Un rayon est constitué d'un point de départ, d'une direction et d'une distance, à savoir : origin
, direction
etdistance
En physique, la distance du rayon est infinie, donc le rayon physique n'a qu'un seul point de départ et une seule direction. Dans le jeu, la distance maximale du rayon est également limitée par le système. Généralement, nous personnalisons la distance, comme par exemple. 1000,0 mètres Ce qui suit est une description de Ray.
Dans Unity, Ray est une structure. Les membres de base du volume de structure incluent.origin
, direction
etGetPoint
C'est-à-dire le point de départ, la direction et la position d'un point à une certaine distance le long du rayon. Voici le code du rayon dans 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);
}
}
D'après le code ci-dessus, on peut voir qu'un rayon peut être construit directement en utilisant le constructeur Ray, par exemple :
Ray ray = new Ray(Vector3.zero, Vector3.forward); // 射线的起点 + 射线的方向
D'après le code ci-dessus, nous pouvons voir que le point de départ du rayon est l'origine des coordonnées du monde dans l'unité (0,0,0), et la direction du rayon est la direction vers l'avant des coordonnées du monde.
En réalité, notre pointeur laser et notre lampe de poche sont visibles, mais les rayons dans Unity sont invisibles. Par conséquent, si nous voulons afficher les rayons, nous pouvons utiliser les méthodes suivantes :
Debug.DrawRay()
rayon d'affichageLineRenderer
Le composant dessine le rayonLe simple fait de construire ou d'afficher les rayons n'a aucun sens. Cela équivaut à tenir un outil dans la main et à travailler sans l'outil.
Comment utiliser les rayons pour la détection d'objets.
Réfléchissez bien : dans notre vie quotidienne, nos pointeurs laser ou nos lampes de poche peuvent afficher des points lumineux sur le mur ou éclairer un certain endroit après avoir émis une lumière laser. Cela montre que le mur peut interagir avec, en d'autres termes, le rayon entre en collision avec. l'objet/ L'objet est détecté. Utilisez l'API suivante dans Unity pour déterminer si l'objet est détecté.
// 基础版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);
Pour utiliser la détection de rayons, vous devez utiliser lePhysics
Bibliothèque, qui contient des fonctions statiques liées à la physique
Vu les fonctions surchargées ci-dessus, nous ne savons souvent pas laquelle utiliser. En fait, nous n'avons besoin que des fonctions de base. Pour celles qui ont de nombreux paramètres, nous utilisons en fait différents paramètres surchargés en fonction des besoins.
Regardez d’abord la version de base de l’API public static bool Raycast(Ray ray);
Selon la valeur de retour, ce que nous pouvons savoir, c'est si le rayon frappe un objet. S'il frappe, il renvoie vrai. Si ce n'est pas le cas, il renvoie faux.
Détection de rayons dans une autre APIpublic static bool Raycast(Ray ray, out RaycastHit hitInfo);
Il y a un autre paramètre danshitInfo
Le paramètre hitInfo est la structure d'information de l'objet touché par le rayon. La structure est relativement grande, ce qui signifie qu'elle contient plus d'informations. C'est la même chose que le résultat de la détection de l'objet touché par le rayon dans Unreal Engine (.FHitResult
) sont similaires d'un point de vue macro ou d'un point de vue pratique, lorsqu'un rayon frappe un objet, nous pouvons obtenir des informations sur l'objet lui-même et des informations sur le point d'impact.
Obtenir les informations d'un objet est facile à comprendre : comme le nom de l'objet, le composant transfrom de l'objet, le Tag de l'objet...
Obtenir les informations du point de frappe, c'est-à-dire les informations d'un point (point de frappe) où le rayon frappe l'objet : comme les coordonnées du point,Normale(normal), plan normal, le point decouleur du sommet…
Ce qui suit estRaycastHit
Informations sur la structure, celles couramment utilisées ont des commentaires ajoutés. Il existe également de nombreuses informations couramment utilisées sans commentaires ajoutés, telles que.lightmapCoord
Ce sont des coordonnées de carte de lumière, utilisées pour le rendu.
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; }
}
}
C'est-à-direHitInfo
Enregistre les informations sur l'objet que nous avons touché, nous pouvons utiliser ces informations pour faire plus de choses
Dans l'unité,layerMask
Il s'agit d'un mécanisme de sélection de couche d'objet utilisé pour contrôler les collisions physiques, la diffusion de rayons, la détection de rayons et d'autres opérations.en définissantlayerMask
, vous pouvez spécifier quels calques doivent être inclus ou exclus de ces opérations.
Revenez à l'API de détection de rayons couramment utilisée public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
milieu.
Dans l'API ci-dessus, il va sans dire que maxDistance est la distance du rayon. Le système a également une valeur maximale définie sur.Mathf.Infinity
. Il existe également un paramètre layerMask dans cette API, qui est le masque de calque.
Pour distinguer les objets du jeu dans Unity, nous pouvons distinguer les objets du jeu en ajoutant des balises, c'est-à-dire en ajoutant des balises. Cependant, les balises sont plus gênantes. Nous devons saisir manuellement le nom de la balise et il est facile de faire des erreurs lors de la saisie manuelle. En même temps, comme il s'agit d'une chaîne, la vitesse de calcul en bas de Unity est un peu plus lente. Il y a un concept de couche dans Unity.
Le layerMask dans Unity contient 32 couches, dont certaines sont déjà utilisées par le système, commePlayer
couche, UI
Couches. Il existe encore de nombreuses couches qui ne sont pas utilisées par le système. Nous pouvons ajouter des couches puis les classer en ajoutant des couches de travail des enfants aux objets du jeu.
Comment ajouter un calque ? Vous devez cliquer sur Calque dans le panneau Inspecteur de n'importe quel objet, puis cliquer surAjouter une coucheVoilà, puis spécifiez manuellement le calque pour les objets qui doivent être modifiés.
Comment l'utiliser après avoir ajouté le calque manuellement.
existerpublic static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
milieulayereMask
Nous avons appris que cela fait unint
Type d'entier, cependant, on ne peut pas remplir les nombres directement, les règles de remplissage utilisent des opérations de décalage,
Comment remplir layerMask :
Obtenir la valeur du masque de calque:
1 << LayerMask.NameToLayer("LayerName")
. Cela renvoie une valeur entière représentant le layerMask de cette couche.Combiner plusieurs couches:
|
. Par exemple,layerMask = LayerMask.GetMask("Layer1", "Layer2")
Un layerMask sera créé, comprenant "Layer1" et "Layer2".exclure un calque:
^
pour exclure des calques spécifiques. Par exemple,layerMask = ~LayerMask.GetMask("ExcludeLayer")
。Vérifier le calque:
layerMask.value & (1 << gameObject.layer)
. Si le résultat n'est pas 0, cela signifie que l'objet est dans 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))
{
// 处理射线击中的对象
}
Voici le code qui utilise le paramètre hitInfo sans et avec le paramètre 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);
}
}
}
Utilisez la détection de rayons pour mettre en œuvre un pointeur laser rotatif Lorsque vous rencontrez un objet, la longueur du rayon est réduite et le rayon doit être dessiné.
Compétences requises : Détection de rayons + Rotation + LineRender
Voici le code
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));
}
}
}
Code optimisé
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));
}
}
Les rendus sont les suivants
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);
}
}
}
}