有没有办法阻止光线投射穿过物体?

3

我正在制作一个抓取枪,如果对象的 Layer轻量级,则将对象向玩家拉近,如果 Layer地面,则将玩家朝向对象拉近。

            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 层的物体,因为我先写了对它的 if 语句。有没有办法让它不因为第一个if语句寻找背后的物体而穿过前面的物体,或者优先选择在前面的物体?

1个回答

4

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

为了更加高效并且实现你想要的结果,只需将两个图层都包含在图层蒙版中,并对这两个图层进行一次单独的光线投射——它会使用给定图层中首先命中的那个。

然后,您仍然可以在if块内检查您实际命中的图层。

因此,我会在检查器中公开该字段以进行配置。

// 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;
}

1
@Brain_Grunt 是的,就像那样。基本上,enum 仍然是一个 int 底层类型(默认情况下..你甚至可以将底层类型更改为例如 byteuint 等)..但这样你就有了一个特定的名称来表示你的值,不必一直记住 01 到底代表什么。由于它们是编译时常量,因此您可以再次使用 switch,这将更有效率。 - derHugo
1
@Brain_Grunt 如果是这种情况,你可以将它作为参数传递给你的方法,或者将其存储在某个类字段中。 - derHugo
1
不使用 var,而是在类级别上拥有一个 private HitType hitType;,然后将其分配给它。 - derHugo
2
在新场景中使用以下代码void Update(){Vector3 dir;if (Input.GetMouseButtonDown(0)) dir = Vector3.forward;else if (Input.GetMouseButtonDown(1)) dir = Vector3.right;else return;int gm = LayerMask.NameToLayer("Default");int lwm = LayerMask.NameToLayer("Water");int layers = 1 << gm | 1 << lwm;if (Physics.Raycast(transform.position, dir, out RaycastHit raycastHit, float.PositiveInfinity, layers)){if (raycastHit.collider.gameObject.layer == gm) Debug.Log("地面"); else if (raycastHit.collider.gameObject.layer == lwm) Debug.Log("轻量级");}}在新场景中放置三个立方体。 - Ruzihm
1
@Brain_Grunt 请解释。不,数字不需要改变。 - Ruzihm
显示剩余13条评论

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