检查Raycast是否命中,是否击中了LayerMask的图层?

时间:2018-11-07 15:58:36

标签: c# unity3d

标题说出来了。

最初我使用的是

hit.transform.gameObject.layer == LayerMask.NameToLayer("Floor")

但是最终我发现我需要在不同楼层使用不同的图层,我认为我应该使用LayerMask,如果我错了但无法正常工作,请更正我。

在文档顶部,我有:

public LayerMask floorLayers;

在无效更新中,我有:

int floorMask = ~floorLayers.value;

在if语句中,我有:

if (playerHasWetFeet == true && wetSteps < maxWetSteps && controller.isGrounded && hit.transform.gameObject.layer == floorMask)

但是这不起作用。

有人可以指出我在做什么吗?

编辑:

这在我的更新功能之内:

int floorMask = ~floorLayers.value;

    currentFrameFootstepLeft = anim.GetFloat("FootstepLeft");

    if (currentFrameFootstepLeft > 0 && lastFrameFootstepLeft < 0)
    {
        if (Physics.Raycast(transform.position, dirDown, out hit, 10f, floorMask))
        {
            if (playerHasWetFeet == true && wetSteps < maxWetSteps && controller.isGrounded && (1 << hit.transform.gameObject.layer & floorMask) != 0)
            {
                LeftWetStepSpawner();
                Debug.Log("Hit");
            }

2 个答案:

答案 0 :(得分:3)

与此:

if(hit.transform.gameObject.layer == floorMask)

您只是比较RaycastHit结果中的图层匹配。如果这确实是您想要的,并且您只想查看按层击中的射线投射,则不要对层进行任何位掩码操作。

删除此

int floorMask = ~floorLayers.value;

获取图层索引:

int floor1 = LayerMask.NameToLayer("Floor1");
int floor2 = LayerMask.NameToLayer("Floor2");
int floor3 = LayerMask.NameToLayer("Floor2");

然后直接比较图层索引:

if (hit.transform.gameObject.layer == floor1)
{

}

if (hit.transform.gameObject.layer == floor2)
{

}

if (hit.transform.gameObject.layer == floor3)
{

}

虽然可以解决您的问题,但使用layermask的主要原因是过滤光线投射。使用layermask时,可以使用它来确定射线投射应击中或忽略哪些对象,如果这是您真正想要做的,请不要像在代码中一样比较该层。只需找到遮罩,然后将遮罩传递给光线投射功能即可。我不确定这是否是您要执行的操作,但是两个示例都应该使您对使用图层蒙版有所了解。

例如,您只想对“地板”层上的对象进行光线投射,而不希望光线投射打到另一层上的任何其他物体:

int floorLayerIndex = LayerMask.NameToLayer("Floor");

//Check if layer is valid
if (floorLayerIndex == -1)
{
    Debug.LogError("Layer Does not exist");
}
else
{
    //Calculate layermask to Raycast to. (Raycast to "Floor" layer only)
    int layerMask = (1 << floorLayerIndex);

    Vector3 fwd = transform.TransformDirection(Vector3.forward);
    RaycastHit hit;

    //Raycast with that layer mask
    if (Physics.Raycast(transform.position, fwd, out hit, 10, layerMask))
    {

    }
}

您可以在this帖子中找到许多其他示例。

答案 1 :(得分:1)

由于您希望光线投射忽略不属于地板的任何物体,因此可以在光线投射中使用遮罩,使其仅撞击地板。为此,您希望拥有LayerMask floorLayers,以便只检查楼层,然后在Raycast中:

Physics.Raycast(transform.position, dirDown, out hit, 10f, ~floorLayers.value)

如果您执行此操作,则任何命中都将是无效命中,并且您无需在下面进行任何数学运算。

如果您以后决定不能对光线投射使用相同的蒙版(也许您真的需要光线投射才能与众多可能的目标发生碰撞,然后查看是否命中的物体碰巧设为地板),然后阅读以下内容。


首先,您要比较一个掩码值,该掩码值的位仅对于楼层(设置为floorLayers.value)设置为true。

如果要将GameObject.layerLayerMask.value进行比较,则首先需要将GameObject.layer移一点。

此外,如果要检查gameObject.layerfloorMask之间的至少一个匹配项,则要使用二进制AND(&)并查看它是否不为0({{ 1}}是不必要的,但有助于提高可读性):

!= 0

这是因为... && (1 << hit.transform.gameObject.layer & floorLayers.value) != 0是该单层的 index ,但是GameObject.layer是基于各种位的真/假值的位掩码。直接比较它们而不先进行转换是没有意义的。