τα στοιχεία επικοινωνίας μου
Ταχυδρομείο[email protected]
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Η ανίχνευση ακτίνων, σύμφωνα με το όνομα, χρησιμοποιεί μια ακτίνα για να ανιχνεύσει εάν χτυπά ένα αντικείμενο/πολλά αντικείμενα
Ο ακτινολογικός έλεγχος αποτελείται από δύο μέρη: ΑκτίνεςκαιΑνίχνευση
Οι ακτίνες μπορούν να φανούν σε πολλά σημεία της καθημερινής ζωής, όπως π.χφακός,στυλό περιστροφής σελίδας με λέιζερ ppt, στη μέση των ετών QingyuΚύκλωπας
Μια ακτίνα αποτελείται από ένα σημείο εκκίνησης, μια κατεύθυνση και μια απόσταση, δηλαδή: origin
, direction
καιdistance
Στη φυσική, η απόσταση της ακτίνας είναι άπειρη, επομένως η φυσική ακτίνα έχει μόνο ένα σημείο εκκίνησης και μία κατεύθυνση Στο παιχνίδι, η μέγιστη απόσταση της ακτίνας περιορίζεται επίσης από το σύστημα 1000,0 μέτρα Ακολουθεί περιγραφή του Ray.
Στο Unity, το Ray είναι μια δομή Τα βασικά μέλη του όγκου της δομής περιλαμβάνουνorigin
, direction
καιGetPoint
Δηλαδή, το σημείο εκκίνησης, η κατεύθυνση και η θέση ενός σημείου σε μια ορισμένη απόσταση κατά μήκος της ακτίνας
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);
}
}
Σύμφωνα με τον παραπάνω κώδικα, μπορεί να φανεί ότι μια ακτίνα μπορεί να κατασκευαστεί απευθείας χρησιμοποιώντας τον κατασκευαστή Ray, για παράδειγμα:
Ray ray = new Ray(Vector3.zero, Vector3.forward); // 射线的起点 + 射线的方向
Σύμφωνα με τον παραπάνω κώδικα, μπορούμε να δούμε ότι το σημείο εκκίνησης της ακτίνας είναι η αρχή των συντεταγμένων του κόσμου στην ενότητα (0,0,0), και η κατεύθυνση της ακτίνας είναι η προς τα εμπρός κατεύθυνση των συντεταγμένων του κόσμου.
Στην πραγματικότητα, ο δείκτης λέιζερ και ο φακός μας μπορούν να φανούν, αλλά οι ακτίνες στο Unity είναι αόρατες, επομένως, εάν θέλουμε να εμφανίσουμε τις ακτίνες, μπορούμε να χρησιμοποιήσουμε τις ακόλουθες μεθόδους:
Debug.DrawRay()
ακτίνα οθόνηςLineRenderer
Το συστατικό σχεδιάζει την ακτίναΑπλώς η κατασκευή ή η εμφάνιση των ακτίνων δεν έχει νόημα.
Πώς να χρησιμοποιήσετε τις ακτίνες για την ανίχνευση αντικειμένων.
Σκεφτείτε το προσεκτικά: Στην καθημερινή μας ζωή, οι δείκτες λέιζερ ή οι φακοί μας μπορούν να εμφανίσουν φωτεινά σημεία στον τοίχο ή να φωτίσουν ένα συγκεκριμένο σημείο μετά την εκπομπή φωτός λέιζερ το αντικείμενο/ Το αντικείμενο ανιχνεύεται Χρησιμοποιήστε το ακόλουθο API στο Unity για να προσδιορίσετε εάν το αντικείμενο ανιχνεύεται.
// 基础版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);
Για να χρησιμοποιήσετε την ανίχνευση ακτίνων, πρέπει να χρησιμοποιήσετε τοPhysics
Βιβλιοθήκη, η οποία περιέχει στατικές συναρτήσεις που σχετίζονται με τη φυσική
Βλέποντας τις παραπάνω υπερφορτωμένες συναρτήσεις, συχνά δεν ξέρουμε ποια να χρησιμοποιήσουμε. Στην πραγματικότητα, χρειαζόμαστε μόνο τις βασικές παραμέτρους.
Πρώτα κοιτάξτε τη βασική έκδοση του API public static bool Raycast(Ray ray);
Σύμφωνα με την τιμή που επιστρέφει, αυτό που μπορούμε να γνωρίζουμε είναι αν η ακτίνα χτυπά ένα αντικείμενο, επιστρέφει true.
Ανίχνευση ακτίνων σε άλλο APIpublic static bool Raycast(Ray ray, out RaycastHit hitInfo);
Υπάρχει μια ακόμη παράμετρος μέσαhitInfo
Η παράμετρος hitInfo είναι η δομή πληροφοριών του αντικειμένου που χτυπήθηκε από την ακτίνα Η δομή είναι σχετικά μεγάλη, πράγμα που σημαίνει ότι περιέχει περισσότερες πληροφορίες.FHitResult
) είναι παρόμοια Από μακροσκοπική ή πρακτική προοπτική, όταν μια ακτίνα χτυπά ένα αντικείμενο, μπορούμε να λάβουμε πληροφορίες για το ίδιο το αντικείμενο και πληροφορίες για το σημείο πρόσκρουσης.
Η απόκτηση των πληροφοριών ενός αντικειμένου είναι εύκολα κατανοητή: όπως το όνομα του αντικειμένου, το στοιχείο μεταφοράς από το αντικείμενο, η ετικέτα του αντικειμένου...
Λάβετε τις πληροφορίες του σημείου χτυπήματος, δηλαδή τις πληροφορίες ενός σημείου (σημείο πρόσκρουσης) όπου η ακτίνα χτυπά το αντικείμενο: όπως οι συντεταγμένες του σημείου,Κανονικός(κανονικό), κανονικό επίπεδο, το σημείο τουχρώμα κορυφής…
Το παρακάτω είναιRaycastHit
Πληροφορίες δομής, οι κοινώς χρησιμοποιούμενες έχουν προσθέσει σχόλια Υπάρχουν επίσης πολλά κοινά χρησιμοποιούμενα χωρίς προσθήκη σχολίων, όπως π.χlightmapCoord
Είναι ελαφριές συντεταγμένες χάρτη, που χρησιμοποιούνται για απόδοση.
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; }
}
}
ΔηλαδήHitInfo
Αποθηκεύει τις πληροφορίες σχετικά με το αντικείμενο που χτυπήσαμε, μπορούμε να χρησιμοποιήσουμε αυτές τις πληροφορίες για να κάνουμε περισσότερα πράγματα
Στην ενότητα,layerMask
Είναι ένας μηχανισμός επιλογής στρώματος αντικειμένου που χρησιμοποιείται για τον έλεγχο της φυσικής σύγκρουσης, της χύτευσης ακτίνων, της ανίχνευσης ακτίνων και άλλων λειτουργιών.με ρύθμισηlayerMask
, μπορείτε να καθορίσετε ποια επίπεδα πρέπει να συμπεριληφθούν ή να εξαιρεθούν από αυτές τις λειτουργίες.
Συνεχίστε πίσω στο API ανίχνευσης ακτίνων που χρησιμοποιείται συνήθως public static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
Μέσης.
Στο παραπάνω API, είναι αυτονόητο ότι το maxDistance είναι η απόσταση της ακτίνας Το σύστημα έχει επίσης μια μέγιστη τιμήMathf.Infinity
Υπάρχει επίσης μια παράμετρος layerMask σε αυτό το API, η οποία είναι η μάσκα επιπέδου.
Για να διακρίνουμε τα αντικείμενα του παιχνιδιού στο Unity, μπορούμε να διακρίνουμε τα αντικείμενα του παιχνιδιού προσθέτοντας ετικέτες, δηλαδή προσθέτοντας ετικέτες. Ωστόσο, οι ετικέτες είναι πιο ενοχλητικές. Ταυτόχρονα, επειδή είναι μια συμβολοσειρά, η ταχύτητα υπολογισμού στο κάτω μέρος του Unity είναι λίγο πιο αργή. Υπάρχει μια έννοια του επιπέδου στο Unity.
Το layerMask στο Unity περιέχει 32 επίπεδα, μερικά από τα οποία χρησιμοποιούνται ήδη από το σύστημα, όπως π.χPlayer
στρώμα, UI
Επίπεδα Υπάρχουν ακόμα πολλά επίπεδα που δεν χρησιμοποιούνται από το σύστημα.
Πώς να προσθέσετε ένα επίπεδο Πρέπει να κάνετε κλικ στο Layer στον πίνακα επιθεώρησης οποιουδήποτε αντικειμένου και, στη συνέχεια, να κάνετε κλικAddLayerΑυτό είναι όλο και, στη συνέχεια, καθορίστε με μη αυτόματο τρόπο το επίπεδο για τα αντικείμενα που πρέπει να τροποποιηθούν.
Πώς να το χρησιμοποιήσετε μετά την μη αυτόματη προσθήκη του επιπέδου.
υπάρχειpublic static bool Raycast(Ray ray, out RaycastHit hitInfo, float maxDistance, int layerMask);
ΜέσηςlayereMask
Μάθαμε ότι κάνει αint
Τύπος ακέραιου, ωστόσο, δεν μπορούμε να συμπληρώσουμε τους αριθμούς απευθείας, οι κανόνες πλήρωσης χρησιμοποιούν πράξεις μετατόπισης,
Πώς να συμπληρώσετε layerMask:
Λάβετε την τιμή Layer Mask:
1 << LayerMask.NameToLayer("LayerName")
. Αυτό επιστρέφει μια ακέραια τιμή που αντιπροσωπεύει το layerMask για αυτό το επίπεδο.Συνδυάστε πολλαπλά στρώματα:
|
. Για παράδειγμα,layerMask = LayerMask.GetMask("Layer1", "Layer2")
Θα δημιουργηθεί ένα layerMask, συμπεριλαμβανομένων των "Layer1" και "Layer2".εξαίρεση στρώματος:
^
για να εξαιρεθούν συγκεκριμένα επίπεδα. Για παράδειγμα,layerMask = ~LayerMask.GetMask("ExcludeLayer")
。Ελέγξτε το στρώμα:
layerMask.value & (1 << gameObject.layer)
. Εάν το αποτέλεσμα δεν είναι 0, σημαίνει ότι το αντικείμενο βρίσκεται σε 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))
{
// 处理射线击中的对象
}
Ο παρακάτω είναι ο κώδικας που χρησιμοποιεί την παράμετρο hitInfo χωρίς και με την παράμετρο 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);
}
}
}
Χρησιμοποιήστε ανίχνευση ακτίνων για να εφαρμόσετε έναν περιστρεφόμενο δείκτη λέιζερ Όταν αντιμετωπίζετε ένα αντικείμενο, το μήκος ακτίνας μειώνεται και η ακτίνα πρέπει να σχεδιαστεί.
Απαιτούμενες δεξιότητες: Ray Detection + Rotation + LineRender
Ακολουθεί ο κωδικός
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));
}
}
}
Βελτιστοποιημένος κώδικας
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));
}
}
Οι αποδόσεις είναι οι εξής
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);
}
}
}
}