unity Physics.RaycastNonAlloc

Physics.RaycastNonAlloc 是 Unity 中用于 3D 物理射線檢測的高性能方法,它是 Physics.Raycast 的非分配版本。

方法簽名

public static int RaycastNonAlloc(Ray ray, RaycastHit[] results, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)public static int RaycastNonAlloc(Vector3 origin, Vector3 direction, RaycastHit[] results, float maxDistance = Mathf.Infinity, int layerMask = DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction = QueryTriggerInteraction.UseGlobal)

參數說明

  • ray/origin+direction: 射線或起點+方向
  • results: 預分配的 RaycastHit 數組
  • maxDistance: 射線最大距離
  • layerMask: 層級掩碼
  • queryTriggerInteraction: 是否檢測觸發器

數組大小限制的重要性

問題說明

當可能擊中的目標數量超過 results 數組的大小時,超出容量的擊中目標將被忽略,這可能導致重要的碰撞檢測被遺漏。

演示示例

using UnityEngine;public class RaycastLimitationDemo : MonoBehaviour
{[SerializeField] private int arraySize = 3;[SerializeField] private float rayDistance = 100f;private RaycastHit[] smallArray;private RaycastHit[] largeArray;void Start(){smallArray = new RaycastHit[arraySize];      // 小數組largeArray = new RaycastHit[50];             // 大數組}void Update(){if (Input.GetKeyDown(KeyCode.Space)){CompareRaycastResults();}}void CompareRaycastResults(){Vector3 origin = transform.position;Vector3 direction = transform.forward;// 使用小數組檢測int smallHitCount = Physics.RaycastNonAlloc(origin, direction, smallArray, rayDistance);// 使用大數組檢測int largeHitCount = Physics.RaycastNonAlloc(origin, direction, largeArray, rayDistance);Debug.Log($"小數組(大小:{arraySize})檢測到: {smallHitCount} 個目標");Debug.Log($"大數組(大小:50)檢測到: {largeHitCount} 個目標");if (largeHitCount > smallHitCount){Debug.LogWarning($"?? 遺漏了 {largeHitCount - smallHitCount} 個目標!");// 顯示被遺漏的目標for (int i = smallHitCount; i < largeHitCount; i++){Debug.LogWarning($"遺漏目標: {largeArray[i].collider.name} (距離: {largeArray[i].distance:F2})");}}}
}

實際問題場景

1. 子彈穿透系統問題

public class BulletPenetration : MonoBehaviour
{[SerializeField] private int maxPenetrations = 3;private RaycastHit[] hits;void Start(){// ? 錯誤:數組太小,可能遺漏目標hits = new RaycastHit[maxPenetrations];}public void FireBullet(Vector3 origin, Vector3 direction, float range){int hitCount = Physics.RaycastNonAlloc(origin, direction, hits, range);Debug.Log($"檢測到 {hitCount} 個目標");// 問題:如果路徑上有5個目標,但數組只能容納3個// 最后2個目標不會被檢測到,即使它們在射線路徑上for (int i = 0; i < hitCount && i < maxPenetrations; i++){ProcessHit(hits[i]);}}void ProcessHit(RaycastHit hit){Debug.Log($"擊中: {hit.collider.name}");}
}

2. 改進的解決方案

public class ImprovedBulletPenetration : MonoBehaviour
{[SerializeField] private int maxPenetrations = 3;[SerializeField] private int maxDetectionTargets = 20; // 增大檢測容量private RaycastHit[] allHits;void Start(){// ? 正確:使用更大的數組確保不遺漏目標allHits = new RaycastHit[maxDetectionTargets];}public void FireBullet(Vector3 origin, Vector3 direction, float range){int totalHits = Physics.RaycastNonAlloc(origin, direction, allHits, range);Debug.Log($"路徑上共檢測到 {totalHits} 個目標");// 根據距離排序(RaycastNonAlloc 默認已按距離排序)int processedHits = 0;for (int i = 0; i < totalHits && processedHits < maxPenetrations; i++){if (CanPenetrate(allHits[i])){ProcessHit(allHits[i]);processedHits++;}else{// 遇到無法穿透的目標,停止處理ProcessHit(allHits[i]);break;}}// 顯示未處理的目標(因為穿透限制)if (totalHits > processedHits){Debug.Log($"因穿透限制,忽略了后續 {totalHits - processedHits} 個目標");}}bool CanPenetrate(RaycastHit hit){// 檢查材質或標簽決定是否可穿透return hit.collider.CompareTag("Penetrable");}void ProcessHit(RaycastHit hit){Debug.Log($"處理擊中: {hit.collider.name} (距離: {hit.distance:F2})");}
}

3. 動態數組大小管理

public class DynamicRaycastSystem : MonoBehaviour
{private RaycastHit[] raycastBuffer;private int currentBufferSize = 10;private const int MAX_BUFFER_SIZE = 100;void Start(){raycastBuffer = new RaycastHit[currentBufferSize];}public RaycastHit[] PerformRaycast(Vector3 origin, Vector3 direction, float distance){int attempts = 0;int hitCount;do{hitCount = Physics.RaycastNonAlloc(origin, direction, raycastBuffer, distance);// 如果數組已滿,說明可能還有更多目標if (hitCount == raycastBuffer.Length && currentBufferSize < MAX_BUFFER_SIZE){// 擴大數組currentBufferSize = Mathf.Min(currentBufferSize * 2, MAX_BUFFER_SIZE);raycastBuffer = new RaycastHit[currentBufferSize];Debug.LogWarning($"擴大射線檢測緩沖區至 {currentBufferSize}");attempts++;}else{break;}}while (attempts < 3); // 最多嘗試3次擴展// 返回實際擊中的結果RaycastHit[] results = new RaycastHit[hitCount];System.Array.Copy(raycastBuffer, results, hitCount);return results;}
}

最佳實踐建議

1. 合理估算數組大小

public class RaycastBestPractices : MonoBehaviour
{// 根據場景復雜度設置緩沖區大小private RaycastHit[] hits;void Start(){// 分析你的場景:// - 最密集區域可能有多少個碰撞器?// - 射線最長距離內可能遇到多少目標?// - 加上安全余量int estimatedMaxTargets = AnalyzeSceneComplexity();int safetyBuffer = estimatedMaxTargets / 2;int bufferSize = estimatedMaxTargets + safetyBuffer;hits = new RaycastHit[bufferSize];Debug.Log($"射線檢測緩沖區大小: {bufferSize}");}int AnalyzeSceneComplexity(){// 簡單的場景復雜度分析Collider[] allColliders = FindObjectsOfType<Collider>();// 可以根據場景大小、碰撞器密度等因素計算return Mathf.Max(20, allColliders.Length / 10);}
}

2. 性能監控

public class RaycastPerformanceMonitor : MonoBehaviour
{private RaycastHit[] hits = new RaycastHit[50];private int maxHitsRecorded = 0;void Update(){if (Input.GetMouseButton(0)){PerformMonitoredRaycast();}}void PerformMonitoredRaycast(){Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);int hitCount = Physics.RaycastNonAlloc(ray, hits, 100f);// 記錄最大擊中數if (hitCount > maxHitsRecorded){maxHitsRecorded = hitCount;Debug.Log($"新的最大擊中數記錄: {maxHitsRecorded}");}// 檢查是否接近數組限制if (hitCount >= hits.Length * 0.8f){Debug.LogWarning($"射線檢測接近緩沖區限制!當前: {hitCount}/{hits.Length}");}}void OnGUI(){GUI.Label(new Rect(10, 10, 300, 20), $"最大擊中記錄: {maxHitsRecorded}");GUI.Label(new Rect(10, 30, 300, 20), $"緩沖區大小: {hits.Length}");}
}

總結

使用 Physics.RaycastNonAlloc 時,數組大小的選擇至關重要:

  1. 過小的數組:會導致遺漏目標,可能影響游戲邏輯
  2. 過大的數組:浪費內存,但確保完整性
  3. 最佳實踐:根據場景復雜度合理估算,加上安全余量
  4. 監控機制:在開發階段監控實際使用情況,調整數組大小

記住:寧可數組稍大一些,也不要因為大小不足而遺漏重要的碰撞檢測

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/91861.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/91861.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/91861.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

數據庫(five day finally)——物物而不物于物,念念而不念于念。(數據庫到此結束!祝世間美好與各位不期而遇,善意常伴汝身!)

1.子查詢&#xff08;1&#xff09;where 子查詢①多行單列配合in和not in操作&#xff08;類似于數據范圍查詢&#xff09;例&#xff1a;顯示工資與各個經理相同的雇員信息&#xff08;包含經理本身&#xff09;。select * from empwhere sal(select sal from emp where jobM…

【甲烷數據集】Sentinel-5P 衛星獲取的全球甲烷數據集-TROPOMI L2 CH?

目錄 數據概述 傳感器 & 衛星信息 監測目標:甲烷(CH?) 數據產品內容 空間與時間覆蓋 云篩選與協同觀測 技術文檔資源 數據下載 Python 代碼繪制 CH4 數據 參考 數據概述 Sentinel-5 Precursor Level 2 Methane (TROPOMI L2 CH?) 數據集是由歐洲哥白尼計劃的 Sentinel…

【數據結構】單鏈表練習(有環)

1.判斷是否是環形鏈表 141. 環形鏈表 - 力扣&#xff08;LeetCode&#xff09; bool hasCycle(struct ListNode *head) {struct ListNode *fast,*slow;fastslowhead;while(fast&&fast->next){fastfast->next->next;slowslow->next;if(fastslow)return tr…

VR 污水廠初體驗:顛覆傳統認知?

第一次戴上 VR 設備走進 VR 污水廠時&#xff0c;那種震撼的感覺至今難以忘懷。仿佛一瞬間&#xff0c;我被傳送到了一個全新的世界&#xff0c;平日里只能在圖紙或實地看到的污水廠&#xff0c;此刻就立體地呈現在眼前。腳下是縱橫交錯的管道&#xff0c;頭頂巨大的處理設備有…

父類 div 自適應高度 子類如何撐滿其高度

使用絕對定位 如果你想要子元素完全撐滿父元素的高度&#xff0c;可以使用絕對定位。這種方法適用于當子元素需要完全覆蓋父元素時。<div class"parent"><div class"child"><!-- 子類內容 --></div> </div>.parent {positio…

從0開始學習R語言--Day51--PH檢驗

在用cox回歸做分析時&#xff0c;我們一般會得出各種變量在結局的風險影響&#xff08;HR大于1&#xff0c;就代表變量值增大&#xff0c;對應結局影響的風險就隨之增大&#xff09;&#xff0c;但是這里有個壞處是&#xff0c;cox回歸得到的是瞬時風險值&#xff0c;我們最多得…

Docker 網絡原理

Linux 常見網絡虛擬化 虛擬網卡:tun/tap虛擬網卡&#xff08;又稱虛擬網絡適配器&#xff09;&#xff0c;即用軟件模擬網絡環境&#xff0c;模擬網絡適配器。在計算機網絡中&#xff0c;tun 與 tap 是操作系統內核中的虛擬網絡設備。不同于普通靠硬件網絡適配器實現的設備&…

【通識】PCB文件

1. PCB文件的導入 在PORTEL99 PCB編輯器的文件菜單中選擇導入先前繪制的CAD文件。導入成功后&#xff0c;編輯器將顯示出元件封裝的基本圖形&#xff0c;為后續操作奠定基礎。將需要抄板的PCB放置于掃描儀中隨后啟動掃描儀&#xff0c;之后啟動AUTO CAD軟件&#xff0c;之后插入…

分布式彈性故障處理框架——Polly(1)

1 前言之服務雪崩 在我們實施微服務之后&#xff0c;服務間的調用變得異常頻繁&#xff0c;多個服務之前可能存在互相依賴的關系&#xff0c;當某個服務出現故障或者是因為服務間的網絡出現故障&#xff0c;導致服務調用的失敗&#xff0c;進而影響到某個業務服務處理失敗&…

【機器學習深度學習】大模型推理速度與私有化部署的價值分析

目錄 前言 一、主流推理框架速度對比 二、為什么 HuggingFace 框架更適合微調驗證&#xff1f; 三、大模型私有化部署的必要性分析 ? 私有化部署的主要動因 1. 數據隱私與業務安全 2. 可控性與性能保障 ? 哪些情況不建議私有部署&#xff1f; 四、總結與選型建議 &…

elementui-admin構建

1、vue-element-admin vue-element-admin是基于element-ui 的一套后臺管理系統集成方案。 功能&#xff1a;介紹 | vue-element-adminA magical vue adminhttps://panjiachen.github.io/vue-element-admin-site/zh/guide/# GitHub地址&#xff1a;https://github.com/PanJia…

深入排查:編譯環境(JDK)與運行環境(JRE/JDK)不一致時的常見 Java 錯誤及解決方案

深入排查&#xff1a;編譯環境&#xff08;JDK&#xff09;與運行環境&#xff08;JRE/JDK&#xff09;不一致時的常見 Java 錯誤及解決方案 在后端 Java 項目中&#xff0c;編譯環境&#xff08;JDK&#xff09; 與 運行環境&#xff08;JRE/JDK&#xff09; 版本不一致&…

[JS逆向] 微信小程序逆向工程實戰

博客配套代碼與工具發布于github&#xff1a;微信小程序 &#xff08;歡迎順手Star一下?&#xff09; 相關爬蟲專欄&#xff1a;JS逆向爬蟲實戰 爬蟲知識點合集 爬蟲實戰案例 逆向知識點合集 前言&#xff1a; 微信小程序對于很多嘗試JS逆向的人群來說&#xff0c;都是一個…

基于5G系統的打孔LDPC編碼和均勻量化NMS譯碼算法matlab性能仿真

目錄 1.引言 2.算法仿真效果演示 3.數據集格式或算法參數簡介 4.算法涉及理論知識概要 4.1打孔技術 4.2 均勻量化NMS譯碼 5.參考文獻 6.完整算法代碼文件獲得 1.引言 在5G通信系統中&#xff0c;信道編碼技術是保障高速率、高可靠性數據傳輸的核心支撐&#xff0c;而低…

基于Java標準庫讀取CSV實現天地圖POI分類快速導入PostGIS數據庫實戰

目錄 前言 一、天地圖POI分類簡介 1、數據表格 2、分類結構 二、從CSV導入到PG數據庫 1、CSV解析流程 2、數據轉換及入庫 3、入庫成果及檢索 三、總結 前言 在之前的博客中&#xff0c;曾經對高德地圖和百度地圖的POI分類以及使用PostGIS數據庫來進行管理的模式進行了詳…

人-AI交互中的信息論不同于傳統的信息論,其信息的增量≠不確定性的減量

在人機交互&#xff08;Human-AI Interaction, HAI&#xff09;領域&#xff0c;信息論的應用確實與傳統的信息論有所不同。這種差異主要源于人機交互HAI中信息的復雜性、動態性以及人類認知的特點。1. 傳統信息論的核心概念傳統信息論由克勞德香農&#xff08;Claude Shannon&…

K8s 通過 Scheduler Extender 實現自定義調度邏輯

1. 為什么需要自定義調度邏輯 什么是所謂的調度? 所謂調度就是指給 Pod 對象的 spec.nodeName 賦值 待調度對象則是所有 spec.nodeName 為空的 Pod 調度過程則是從集群現有的 Node 中為當前 Pod 選擇一個最合適的 實際上 Pod 上還有一個平時比較少關注的屬性&#xff1a;…

7.19 換根dp | vpp |滑窗

lcr147.最小棧通過兩個棧 維護實現class MinStack { public:stack<int> A, B;MinStack() {}void push(int x) {A.push(x);if(B.empty() || B.top() > x)B.push(x);}void pop() {if(A.top() B.top())B.pop();A.pop();}int top() {return A.top();}int getMin() {retur…

以太坊的心臟與大腦:詳解執行客戶端(EL)與共識客戶端(CL)

好的&#xff0c;各位技術同道&#xff0c;歡迎再次光臨我的博客。在上一篇文章中&#xff0c;我們聊了如何搭建一個以太坊測試節點&#xff0c;并提到了節點需要同時運行“執行客戶端”和“共識客戶端”。很多朋友對此表示了濃厚興趣&#xff0c;想深入了解這兩者究竟是什么&a…

Debian-10,用glibc二進制預編譯包,安裝Mysql-5.7.44 筆記250716

Debian-10,用glibc二進制預編譯包,安裝Mysql-5.7.44 筆記250716 &#x1f4e6; 一步腳本 #!/bin/bash### 安裝依賴 apt install -y libaio1 libnuma1 libncurses5### 下載MySQL-5.7.44 的 glib二進制包: mysql-5.7.44-linux-glibc2.12-x86_64.tar.gz ,(如果不存在) mkdir…