【问题标题】:Checking if the Raycast hit, hits a layer from the LayerMask?检查 Raycast 是否命中了来自 LayerMask 的图层?
【发布时间】:2018-11-08 01:12:47
【问题描述】:

标题说明了一切。

最初我使用的是:

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");
            }

【问题讨论】:

  • floorLayers 是否设置为选择每个地板层,这使得floorMask 选择所有不是地板的东西?在这种情况下,如果您完全删除 if 语句的最后一部分会发生什么?
  • 经过一些测试,我让它工作了,但它是倒置的。我已经选择了我希望光线投射命中的 2 层,但事实证明我必须选择除了我想要的 2 层之外的所有内容。有没有办法反转这个?
  • 反转Raycast 调用中的最后一个参数,如果~ 已经存在,则删除它。
  • 就是这样,非常感谢!

标签: c# unity3d


【解决方案1】:

有了这个:

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");

然后直接比较Layer index:

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

}

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

}

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

}

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

例如,您只想对“Floor”层上的对象进行光线投射,并且不希望光线投射到另一层上的任何其他对象:

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 帖子上找到许多其他示例。

【讨论】:

    【解决方案2】:

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

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

    如果你这样做,任何击中都将是地板击中,你不需要在下面做任何数学运算。

    如果你后来决定不能对光线投射使用相同的遮罩(也许你真的需要光线投射能够与许多可能的目标发生碰撞然后看看被击中的物体是否碰巧是地板),然后阅读下文。


    首先,您想要比较一个掩码值,该掩码值的位设置为仅适用于楼层的真,这似乎是floorLayers.value

    如果要将GameObject.layerLayerMask.value 进行比较,您首先需要移动GameObject.layer 位。

    另外,如果您想检查gameObject.layerfloorMask 之间的至少一个匹配项,您需要使用二进制 AND (&amp;) 并查看它是否不为 0(!= 0 是不必要的,但它可以有助于提高可读性):

    ... &amp;&amp; (1 &lt;&lt; hit.transform.gameObject.layer &amp; floorLayers.value) != 0

    这是因为GameObject.layer 是该单层的索引,而FloorMask.value 是一个位掩码,它基于各种位的真/假值。不先进行转换,直接比较是没有意义的。

    【讨论】:

    • 感谢您的快速回复,不幸的是它仍然无法正常工作。我想要实现的是,如果它碰到图层蒙版中的任何图层,它应该做一些事情,在我的例子中,实例化一个预制件。
    • @QuincyNorbert 我没有意识到单个floorMask 中有多个层。如果是这种情况,并且您将floorLayers.value 放入Physics.Raycast,那么 any hit 不是已经满足该条件了吗?无论如何,我编辑了我的答案以解决包含多个层的~LayerMask.value
    • 由于某种原因我仍然无法让它工作,我将用更多的代码更新帖子,以了解它现在是如何设置的。
    猜你喜欢
    • 1970-01-01
    • 2017-08-21
    • 2022-11-21
    • 2013-06-25
    • 1970-01-01
    • 2010-11-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多