当前位置:   article > 正文

Unity 射线检测方法及其应用场景优化指南_physics.raycastnonalloc

physics.raycastnonalloc

Unity 开发中,射线检测是一个非常重要的功能,广泛应用于碰撞检测、物理交互等场景。合理选择和使用射线检测方法,不仅可以提高检测的准确性,还能显著优化性能。

今天在学习中突然想到游戏中频繁的使用射线,GC 也会大量产生 

如何进行优化呢 ? 

射线检测方法概览
  1. Physics.Raycast
  2. Physics.RaycastAll
  3. Physics.RaycastNonAlloc
  4. Physics.SphereCast
  5. Physics.SphereCastAll
  6. Physics.SphereCastNonAlloc
  7. Physics.CapsuleCast
  8. Physics.CapsuleCastAll
  9. Physics.CapsuleCastNonAlloc

性能优化建议

  1. 选择合适的方法:根据具体需求选择最合适的射线检测方法。如果只需要检测第一个相交物体,使用 Physics.Raycast 而不是 Physics.RaycastAll
  2. 使用 NonAlloc 版本在高频率调用的检测场景中,优先使用 NonAlloc 版本以减少垃圾回收和内存分配。
  3. 优化检测频率:尽量减少不必要的射线检测调用,优化逻辑使射线检测只在需要时调用。
  4. 使用 LayerMask:通过 LayerMask 过滤不必要的碰撞体,提高检测效率。
  5. 合理设计检测区域:避免过大范围的检测区域,合理设计检测区域以减少无效的检测

     Tip: 主体是就是在频繁使用射线检测时候,使用避免GC的方法等等去实现减少GC

射线检测方法及其使用场景

1. Physics.Raycast
  • 描述:检测从起点沿指定方向的射线是否与任何碰撞体相交。
  • 使用场景:用于单一目标的检测,如射击、视线检测、点击物体等
    1. if (Physics.Raycast(origin, direction, out RaycastHit hitInfo, maxDistance, layerMask))
    2. {
    3. // 处理碰撞
    4. }
    2. Physics.RaycastAll
  • 描述:检测从起点沿指定方向的射线与所有相交的碰撞体。
  • 使用场景:需要检测射线路径上所有物体,如激光光束穿过多个目标。
    1. RaycastHit[] hits = Physics.RaycastAll(origin, direction, maxDistance, layerMask);
    2. foreach (RaycastHit hit in hits)
    3. {
    4. // 处理每个碰撞
    5. }
    3. Physics.RaycastNonAlloc
  • 描述:检测从起点沿指定方向的射线与所有相交的碰撞体,结果存储在预先分配的数组中。
  • 使用场景频繁射线检测且希望避免垃圾回收的场景。
    1. if (Physics.SphereCast(origin, radius, direction, out RaycastHit hitInfo, maxDistance, layerMask))
    2. {
    3. // 处理碰撞
    4. }

4. Physics.SphereCast
  • 描述:在指定方向上发射一个球体,检测它是否与任何碰撞体相交。
  • 使用场景:模拟具有体积的物体检测,如角色视野检测、环境扫描。
  1. if (Physics.SphereCast(origin, radius, direction, out RaycastHit hitInfo, maxDistance, layerMask))
  2. {
  3. // 处理碰撞
  4. }
5. Physics.SphereCastAll
  • 描述:在指定方向上发射一个球体,检测它与所有相交的碰撞体。
  • 使用场景:需要检测球体路径上所有相交物体的情况。
    1. RaycastHit[] hits = Physics.SphereCastAll(origin, radius, direction, maxDistance, layerMask);
    2. foreach (RaycastHit hit in hits)
    3. {
    4. // 处理每个碰撞
    5. }

6. Physics.SphereCastNonAlloc
  • 描述:在指定方向上发射一个球体,检测它与所有相交的碰撞体,结果存储在预先分配的数组中。
  • 使用场景频繁球体检测且希望避免垃圾回收的场景。
    1. RaycastHit[] results = new RaycastHit[10];
    2. int hitCount = Physics.SphereCastNonAlloc(origin, radius, direction, results, maxDistance, layerMask);
    3. for (int i = 0; i < hitCount; i++)
    4. {
    5. RaycastHit hit = results[i];
    6. // 处理每个碰撞
    7. }
    7. Physics.CapsuleCast
  • 描述:在指定方向上发射一个胶囊体,检测它是否与任何碰撞体相交。
  • 使用场景:检测具有高度和宽度的物体,如角色的碰撞检测、隧道穿越检测。
  1. if (Physics.CapsuleCast(point1, point2, radius, direction, out RaycastHit hitInfo, maxDistance, layerMask))
  2. {
  3. // 处理碰撞
  4. }

8. Physics.CapsuleCastAll
  • 描述:在指定方向上发射一个胶囊体,检测它与所有相交的碰撞体。
  • 使用场景:需要检测胶囊体路径上所有相交物体的情况。
  1. RaycastHit[] hits = Physics.CapsuleCastAll(point1, point2, radius, direction, maxDistance, layerMask);
  2. foreach (RaycastHit hit in hits)
  3. {
  4. // 处理每个碰撞
  5. }

9. Physics.CapsuleCastNonAlloc
  • 描述:在指定方向上发射一个胶囊体,检测它与所有相交的碰撞体,结果存储在预先分配的数组中。
  • 使用场景:频繁胶囊体检测且希望避免垃圾回收的场景。
    1. RaycastHit[] results = new RaycastHit[10];
    2. int hitCount = Physics.CapsuleCastNonAlloc(point1, point2, radius, direction, results, maxDistance, layerMask);
    3. for (int i = 0; i < hitCount; i++)
    4. {
    5. RaycastHit hit = results[i];
    6. // 处理每个碰撞
    7. }

3.将自定义射线检测写成接口的形式,可以使代码更加灵活和可扩展

  1. using UnityEngine;
  2. public interface IRaycastManager
  3. {
  4. int Raycast(Vector3 origin, Vector3 direction, float maxDistance, LayerMask layerMask, out RaycastHit[] results);
  5. }
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3. public class RaycastManager : MonoBehaviour, IRaycastManager
  4. {
  5. private List<RaycastHit[]> raycastHitPools;
  6. private int poolSize = 10; // 池的大小
  7. private int maxResults = 10; // 每个数组可以存储的最大结果数
  8. void Start()
  9. {
  10. // 初始化对象池
  11. raycastHitPools = new List<RaycastHit[]>(poolSize);
  12. for (int i = 0; i < poolSize; i++)
  13. {
  14. raycastHitPools.Add(new RaycastHit[maxResults]);
  15. }
  16. }
  17. public int Raycast(Vector3 origin, Vector3 direction, float maxDistance, LayerMask layerMask, out RaycastHit[] results)
  18. {
  19. // 从对象池中获取一个预分配的数组
  20. results = GetRaycastHitArrayFromPool();
  21. // 使用 NonAlloc 方法进行射线检测
  22. int hitCount = Physics.RaycastNonAlloc(origin, direction, results, maxDistance, layerMask);
  23. // 返回检测到的碰撞体数量
  24. return hitCount;
  25. }
  26. private RaycastHit[] GetRaycastHitArrayFromPool()
  27. {
  28. // 简单实现:循环使用池中的数组
  29. RaycastHit[] resultArray = raycastHitPools[0];
  30. raycastHitPools.RemoveAt(0);
  31. raycastHitPools.Add(resultArray);
  32. return resultArray;
  33. }
  34. // 调试时绘制射线
  35. void OnDrawGizmos()
  36. {
  37. Gizmos.color = Color.red;
  38. Gizmos.DrawLine(transform.position, transform.position + transform.forward * 10);
  39. }
  40. }
  使用自定义射线检测接口
  1. using UnityEngine;
  2. public class TestRaycast : MonoBehaviour
  3. {
  4. private IRaycastManager raycastManager;
  5. public LayerMask layerMask;
  6. public float maxDistance = 100f;
  7. void Start()
  8. {
  9. // 获取 RaycastManager 组件
  10. raycastManager = GetComponent<RaycastManager>();
  11. }
  12. void Update()
  13. {
  14. // 射线起点和方向
  15. Vector3 origin = transform.position;
  16. Vector3 direction = transform.forward;
  17. // 使用自定义射线检测方法
  18. int hitCount = raycastManager.Raycast(origin, direction, maxDistance, layerMask, out RaycastHit[] results);
  19. // 处理检测结果
  20. for (int i = 0; i < hitCount; i++)
  21. {
  22. RaycastHit hit = results[i];
  23. Debug.Log("Hit: " + hit.collider.name);
  24. }
  25. }
  26. }

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号