Unity射线详解与应用

射线检测是 Unity 中一种高效的空间检测技术,广泛应用于射击游戏、视线检测、物体选取等场景。以下是 Unity 射线系统的全面解析。

射线基础概念

射线(Ray) 是由一个起点和一个方向定义的无限延伸的直线,用于检测这条线上是否存在碰撞体。

核心组件

1. Ray 结构体

Ray ray = new Ray(origin, direction);
  • origin: 射线起点(Vector3)

  • direction: 射线方向(Vector3,需标准化)

2. RaycastHit 结构体

存储射线命中信息,包含:

  • collider: 命中的碰撞体

  • point: 命中点的世界坐标

  • distance: 从射线原点到命中点的距离

  • normal: 命中表面的法线向量

基本射线检测方法

1. Physics.Raycast (静态方法)

// 最简单形式
if (Physics.Raycast(transform.position, transform.forward)) {
    Debug.Log("检测到物体");
}

// 完整参数形式
if (Physics.Raycast(origin, direction, out RaycastHit hit, maxDistance, layerMask, queryTriggerInteraction)) {
    // 使用hit信息
}

参数说明

  • origin: 射线起点

  • direction: 射线方向

  • hit: 输出参数,存储命中信息

  • maxDistance: 射线最大长度(默认无限)

  • layerMask: 层级掩码,指定检测哪些层

  • queryTriggerInteraction: 如何处理触发器(忽略/检测)

2. 摄像机到鼠标位置的射线

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit)) {
    Debug.Log("点击了: " + hit.collider.name);
}

高级射线检测技术

1. 球形射线检测 (SphereCast)

检测沿射线方向的球体体积

if (Physics.SphereCast(origin, radius, direction, out hit, maxDistance)) {
    // 处理球形检测结果
}

2. 盒形射线检测 (BoxCast)

检测沿射线方向的盒子体积

if (Physics.BoxCast(center, halfExtents, direction, out hit, orientation, maxDistance)) {
    // 处理盒形检测结果
}

3. 射线穿透检测 (RaycastAll)

检测射线路径上的所有物体

RaycastHit[] hits = Physics.RaycastAll(ray, maxDistance);
foreach (var hit in hits) {
    // 处理每个命中对象
}

// 按距离排序
Array.Sort(hits, (x, y) => x.distance.CompareTo(y.distance));

4. 非分配型射线检测 (RaycastNonAlloc)

避免GC分配,适合频繁调用

RaycastHit[] results = new RaycastHit[10];
int hitCount = Physics.RaycastNonAlloc(ray, results, maxDistance);
for (int i = 0; i < hitCount; i++) {
    // 处理结果
}

实际应用示例

1. 第一人称射击

void Update() {
    if (Input.GetButtonDown("Fire1")) {
        Ray ray = new Ray(transform.position, transform.forward);
        if (Physics.Raycast(ray, out RaycastHit hit, 100f, enemyLayer)) {
            Enemy enemy = hit.collider.GetComponent();
            if (enemy != null) {
                enemy.TakeDamage(10);
            }
        }
    }
}

2. 视线检测

bool HasLineOfSight(GameObject target) {
    Vector3 direction = target.transform.position - transform.position;
    if (!Physics.Raycast(transform.position, direction, out RaycastHit hit, direction.magnitude, obstacleLayer)) {
        return true;
    }
    return hit.collider.gameObject == target;
}

3. 地面检测

bool isGrounded;
float groundCheckDistance = 0.1f;

void CheckGround() {
    isGrounded = Physics.Raycast(transform.position, Vector3.down, groundCheckDistance, groundLayer);
}

性能优化技巧

层级掩码过滤:始终使用 layerMask 减少不必要的检测

int layerMask = 1 << LayerMask.NameToLayer("Enemy");
Physics.Raycast(..., layerMask);
  1. 限制检测距离:设置合理的 maxDistance

  2. 避免每帧检测:在需要时才进行射线检测

  3. 使用 NonAlloc 方法:减少GC分配

  4. 缓存射线结果:如果结果不会频繁变化

调试与可视化

// 在Scene视图中绘制射线
Debug.DrawRay(start, direction * length, Color.red, duration);

// 在游戏运行时可视化
void OnDrawGizmos() {
    Gizmos.color = Color.green;
    Gizmos.DrawRay(transform.position, transform.forward * 10f);
}

常见问题解决

  1. 射线检测不到物体

    • 确认物体有Collider

    • 检查layerMask设置

    • 确认射线方向正确(建议使用normalized方向)

  2. 性能问题

    • 减少每帧的射线检测数量

    • 使用更简单的碰撞体

  3. 精度问题

    • 对于快速移动物体,考虑使用SphereCast

    • 调整射线起点偏移

你可能感兴趣的:(unity,游戏引擎)