Unity Physics.Raycast似乎无法正确检测到它所击中的物体。

5

我有一个游戏物体实现了UnityEngine.EventSystems中的IDragHandler和IDropHandler接口。

在OnDrop事件中,我想检查这个物体是否在另一个物体的前面被放下。我使用Physics.Raycast进行检测,但只有在某些情况下返回true。我使用屏幕坐标作为射线方向,使用此变换作为Raycast的起点。

我的代码如下:

 public void OnDrop(PointerEventData eventData)
 {
         var screenRay = Camera.main.ScreenPointToRay(new Vector3(eventData.position.x, eventData.position.y, 0.0f));
         var thisToObjectBehind = new Ray(transform.position, screenRay.direction);
         Debug.DrawRay(thisToObjectBehind.origin, thisToObjectBehind.direction, Color.yellow, 20.0f, false);
         RaycastHit hit;
         if (Physics.Raycast(thisToObjectBehind, out hit))
         {
             Debug.LogFormat("Dropped in front of {0}!", hit.transform);
         }
 }

我正在使用透视相机。当物体被放置在屏幕/相机正前方的物体之前时,Physics.Raycast有时会返回true,但“hit”包含的是此物体而不是后面的物体。有时它会返回false。这两种结果都不是预期的,因为在此背后应该存在可以进行Raycast的对象。
当物体被放置在相机视野边缘的物体之前时,Physics.Raycast成功地找到了其后面的对象。
Debug射线看起来很好,它从我放置的物体向后画出,直到它应该命中的物体。

注意:如果我使用thisToObjectBehind = new Ray(transform.position, transform.forward * -1)而不是使用screenRay,那么射线投射将成功,因此碰撞体应该没有问题。但是,我不想限制自己必须面向相机。 - Helena
成功和失败时,eventData的值是什么? - Bizhan
你不需要一个 LayerMask 吗? - Fredrik Schön
Fredrik 绝对正确,图层是问题所在。 - Helena
1个回答

1

将被丢弃的对象暂时放置在IgnoreRaycast层中解决了我的问题。这也意味着我可以跳过将射线原点设置为transform.position的步骤。

    public void OnDrop(PointerEventData eventData)
    {
        // Save the current layer the dropped object is in,
        // and then temporarily place the object in the IgnoreRaycast layer to avoid hitting self with Raycast.
        int oldLayer = gameObject.layer;
        gameObject.layer = 2;

        var screenRay = Camera.main.ScreenPointToRay(new Vector3(eventData.position.x, eventData.position.y, 0.0f));
        RaycastHit hit;
        if (Physics.Raycast(screenRay, out hit))
        {
            Debug.LogFormat("Dropped in front of {0}!", hit.transform);
        }

        // Reset the object's layer to the layer it was in before the drop.
        gameObject.layer = oldLayer;
    }

编辑:由于性能原因,从代码片段中移除了try/finally块。


不要使用Unity的API捕获异常,只在C# IO中这样做。这样做会使您的代码变慢,具体取决于您附加该代码的GameObject数量。只需进行空值检查即可。 - Programmer
一个只有try finally,没有catch的代码块会有多糟糕呢?我只是想确保无论发生什么事情,都能将游戏对象移回之前所在的层级,以避免在调用后出现奇怪的行为。 - Helena
JIT不会对“protected”/“try”块执行优化。 - Programmer
好的,谢谢!我会从答案的代码块中删除try/finally。 - Helena

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接