有什么方法可以阻止光线投射穿过物体吗?

Is there any way to stop raycasts from going through objects?

我正在制作一把抓钩枪,如果层为 LightWeight,它会将物体拉向玩家,如果层为 Ground

,则将玩家拉向物体
            int groundLayer_mask = LayerMask.GetMask("Ground");
            int lightWeightLayer_mask = LayerMask.GetMask("LightWeight");

            //Shoots a raycast, and only works if layer is Ground
            if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, groundLayer_mask))
            {
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 0;

                state = State.HookShotThrown;
            }
            //Shoots a raycast, and only works if layer is LightWeight
            else if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, lightWeightLayer_mask))
            {
                //Hit Something
                debugHitpointTransform.position = raycastHit.point;
                hookshotPosition = raycastHit.point;
                hookShotSize = 0f;
                HookShotTransform.gameObject.SetActive(true);
                HookShotTransform.localScale = Vector3.zero;
                layerHit = 1;

                state = State.HookShotThrown;
            }

但是如果我朝 Ground 层的对象方向看,即使 LightWeight 层的对象比 Ground 层的对象更近,它也会带有 Ground 的那个,因为我先有它的 if 语句。有什么方法可以让它不通过前面的对象只是因为第一个如果正在寻找后面的对象,或者让它优先考虑前面的对象?

除了 layerHit 的值外,您的两个光线投射案例基本上做完全相同的事情。所以无论哪种方式,这都是一种资源浪费 ;)

因此,为了提高效率并实现您想要的效果,只需在图层蒙版中包含两个图层,并对两个图层只进行一次光线投射 -> 它将使用它首先从给定图层命中的任何内容。

然后你仍然可以检查你在 if 块内实际击中的层。

所以我会在 Inspector 中公开该字段以进行配置

// Configure this via the Inspector
// it will be a drop-down from which you can select multiple entries
public LayerMask layers;

private void Awake ()
{
    // if you really want to keep getting these by code
    layers = LayerMask.GetMask("Ground", "LightWeight");
}

而且通常我也会使用 enum 来获得一些有意义的名称,例如

public enum HitType
{
    None = -1,
    Ground,
    Lightweight
}

然后使用像

这样的单一光线投射
int groundLayer_mask = LayerMask.NameToLayer("Ground");
int lightWeightLayer_mask = LayerMask.NameToLayer("LightWeight");

var hitType = HitType.None;

if (Physics.Raycast(Shoulder.transform.position, cam.transform.forward, out raycastHit, float.PositiveInfinity, layers))
{
    //Hit Something
    debugHitpointTransform.position = raycastHit.point;
    hookshotPosition = raycastHit.point;
    hookShotSize = 0f;
    HookShotTransform.gameObject.SetActive(true);
    HookShotTransform.localScale = Vector3.zero;

    if(raycastHit.collider.gameObject.layer == groundLayer_mask) hitType = HitType.Ground;
    else if(raycastHit.collider.gameObject.layer == lightWeightLayer_mask) hitType = HitType.Lightweight;

    state = State.HookShotThrown;
}