You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Unity 3D横向卷轴游戏聚光灯射线检测无法识别障碍物问题求助

Unity 3D横向卷轴游戏聚光灯射线检测无法识别障碍物问题求助

兄弟,我太懂你这种明明视觉上射线完全对准障碍物,但就是死活不命中的崩溃感了!我之前做类似《Projection: First Light》的投影平台系统时,也踩过好几个一模一样的坑,结合你给出的代码和排查细节,咱们一步步把这个问题揪出来解决掉:

1. 先排查最容易踩的「3D空间Z轴错位」坑

你在代码里强制把射线方向的z值设为0:direction.z = 0;,这会让射线严格在XY平面内传播,但如果你的聚光灯Z轴位置和障碍物的Z轴位置不一样——哪怕Scene视图看起来两者重叠,3D空间里射线和障碍物其实是在Z轴方向错开的,自然会直接穿过去。

解决办法:

  • 先检查聚光灯lightSource.position.z和障碍物的position.z是否完全一致,要是有偏移,把射线原点的Z轴对齐到障碍物的Z轴:
    // 假设你障碍物的Z轴都在0位置,直接强制对齐
    Vector3 origin = new Vector3(lightSource.position.x, lightSource.position.y, 0f);
    
  • 或者改用SphereCast代替Raycast,给一个极小的半径,允许Z轴有微小偏移:
    if (Physics.SphereCast(origin, 0.05f, worldDir, out RaycastHit hit, radius, obstacleMask))
    

2. 检查LayerMask是不是悄悄「失效」了

很多时候我们会忽略图层的小问题:比如图层名字拼写错误、没创建对应的「Obstacle」图层,这时候LayerMask.NameToLayer("Obstacle")会返回-1,导致你的obstacleMask变成0——射线检测会直接忽略所有图层,自然不可能命中。

解决办法:

  • GenerateMesh方法开头加个调试日志,确认图层索引是否有效:
    int obstacleLayerIndex = LayerMask.NameToLayer("Obstacle");
    if (obstacleLayerIndex == -1) {
        Debug.LogError("找不到名为Obstacle的图层!快去Edit>Project Settings>Tags and Layers里确认创建");
        return;
    }
    Debug.Log("障碍物图层索引:" + obstacleLayerIndex);
    
  • 也可以直接在Inspector面板手动给obstacleMask赋值,避免代码里的拼写错误。

3. 给射线检测加个「保险」参数

虽然你说障碍物不是Trigger,但如果项目里Physics.queriesHitTriggers被设为false,或者不小心有某个障碍物开了Trigger,射线就会直接跳过。给射线检测加个额外参数就能覆盖这个全局设置:

if (Physics.Raycast(origin, worldDir, out RaycastHit hit, radius, obstacleMask, QueryTriggerInteraction.Collide))

4. 验证射线的「真实」路径和位置

有时候我们依赖Scene视图的视觉判断会出错,不如直接用代码把射线的真实状态打出来:

  • 在射线循环里加持久化的Debug射线(默认Debug.DrawRay只显示一帧,加个时长参数方便观察):
    Debug.DrawRay(origin, worldDir * radius, Color.cyan, 2f);
    
  • 同时给未命中的射线打日志,记录它的原点和方向:
    Debug.Log($"第{i}条射线未命中:原点{origin},方向{worldDir},最大距离{radius}");
    

最后给你修改后的核心代码片段

把上面的排查点整合到你的GenerateMesh方法里,应该能很快定位问题:

void GenerateMesh() {
    if (lightSource == null) return;
    Light spot = lightSource.GetComponent<Light>();
    if (spot == null || spot.type != LightType.Spot) {
        Debug.LogError("请指定有效的聚光灯光源!");
        return;
    }

    // 检查图层有效性
    int obstacleLayerIndex = LayerMask.NameToLayer("Obstacle");
    if (obstacleLayerIndex == -1) {
        Debug.LogError("未找到Obstacle图层,请检查设置");
        return;
    }

    Vector3 origin = lightSource.position;
    // 对齐Z轴到障碍物平面(根据你的场景调整0值)
    origin = new Vector3(origin.x, origin.y, 0f);
    Vector3 forward = lightSource.forward;
    float angleRange = spot.spotAngle;
    float angleStart = -angleRange / 2f;
    float angleStep = angleRange / rayCount;

    List<Vector3> vertices = new List<Vector3>();
    List<int> triangles = new List<int>();
    Vector3 localOrigin = transform.InverseTransformPoint(origin);
    vertices.Add(localOrigin);

    for (int i = 0; i <= rayCount; i++) {
        float angle = angleStart + i * angleStep;
        Quaternion rotation = Quaternion.AngleAxis(angle, Vector3.forward);
        Vector3 direction = rotation * forward;
        // 取消强制Z轴为0,改用对齐后的原点保证Z轴一致
        // direction.z = 0; 
        Vector3 worldDir = direction.normalized;

        // 绘制持久化射线方便调试
        Debug.DrawRay(origin, worldDir * radius, Color.cyan, 2f);

        Vector3 hitPoint = origin + worldDir * radius;
        if (Physics.Raycast(origin, worldDir, out RaycastHit hit, radius, obstacleMask, QueryTriggerInteraction.Collide)) {
            Debug.Log("命中障碍物:" + hit.collider.name);
            hitPoint = hit.point;
        } else {
            Debug.Log($"射线{i}未命中:原点{origin},方向{worldDir}");
        }
        vertices.Add(transform.InverseTransformPoint(hitPoint));
    }

    // 网格生成的后续代码保持不变...
    for (int i = 1; i < vertices.Count - 1; i++) {
        triangles.Add(0);
        triangles.Add(i + 1);
        triangles.Add(i);
    }

    mesh.Clear();
    mesh.SetVertices(vertices);
    mesh.SetTriangles(triangles, 0);
    mesh.RecalculateNormals();
    mesh.RecalculateBounds();
    meshCollider.sharedMesh = null;
    meshCollider.sharedMesh = mesh;
}

按照上面的步骤排查,大概率是Z轴错位或者LayerMask的问题,先从这两点入手,应该很快就能解决射线不命中的问题!

内容来源于stack exchange

火山引擎 最新活动