多个光线投射,只有两个有效。

4

我正在开发一款AI,并希望为它提供玩家(汽车)与游戏中(墙壁、街道中心、其他汽车等)几乎所有元素之间的距离。我使用的是Physics.Raycast技术。但问题在于只有DistanceToRightSideOfMOTS(MOTS:街道中心)和DistanceToBackWall能够正常工作。以下是我的代码:

private void FixedUpdate()
{
    RequestDecision();
    RequestAction();

     // Get the distances to the walls

    // Get distance to left wall
    RaycastHit hit;
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 25, 1 << 11))
    {
        DistanceToLeftWall = hit.distance / 25;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.left) * hit.distance, Color.red);
    }
    else
    {
        DistanceToLeftWall = 1;
    }

    // Get distance to right wall
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.right), out hit, 25, 1 << 12))
    {
        DistanceToRightWall = hit.distance / 25;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.right) * hit.distance, Color.red);
    }
    else
    {
        DistanceToRightWall = 1;
    }

    // Get distance to front wall (it sees 2x farther because it's hard to turn on the corner)
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, 50, (1 << 11) | (1 << 12)))
    {
        DistanceToFrontWall = hit.distance / 50;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.red);
    }
    else
    {
        DistanceToFrontWall = 1;
    }
    // Get distance to back wall
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.back), out hit, 50, (1 << 11) | (1 << 12)))
    {
        DistanceToBackWall = hit.distance / 50;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.back) * hit.distance, Color.red);
    }
    else
    {
        DistanceToBackWall = 1;
    }

    //////////////////

    // Get the distance to other cars

    /////////////////

    // Get distance to left car
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 25, 1 << 13))
    {
        DistanceToLeftCar = hit.distance / 25;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.left) * hit.distance, Color.green);
    }
    else
    {
        DistanceToLeftCar = 1;
    }

    // Get distance to right car
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.right), out hit, 25, 1 << 13))
    {
        DistanceToRightCar = hit.distance / 25;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.right) * hit.distance, Color.green);
    }
    else
    {
        DistanceToRightCar = 1;
    }

    // Get distance to front car
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.forward), out hit, 50, 1 << 13))
    {
        DistanceToFrontCar = hit.distance / 50; // We divide the distance to normalize the input
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.forward) * hit.distance, Color.green);
    }
    else
    {
        DistanceToFrontCar = 1;
    }
    // Get distance to back car
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.back), out hit, 50, 1 << 13))
    {
        DistanceToBackCar = hit.distance / 50;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.back) * hit.distance, Color.green);
    }
    else
    {
        DistanceToBackCar = 1;
    }


    //Get distances to the middle of the street


    //Get distance from the left side
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 10, 1 << 14))
    {
        DistanceToLeftSideOfMOTS = hit.distance / 10;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.left) * hit.distance, Color.blue);
    }
    else
    {
        DistanceToLeftSideOfMOTS = 1;
    }
    //Get distance from the right side
    if (Physics.Raycast(transform.position, transform.TransformDirection(Vector3.right), out hit, 10, 1 << 14))
    {
        DistanceToRightSideOfMOTS = hit.distance / 10;
        Debug.DrawRay(transform.position, transform.TransformDirection(Vector3.right) * hit.distance, Color.blue);
    }
    else
    {
        DistanceToRightSideOfMOTS = 1;
    }

}

其他距离始终返回1,即使它不应该。为什么不起作用,我该怎么解决?
编辑1:我不知道为什么,但当我把车子开得离右侧墙很近时,DistanceToRightWall开始工作,只有当我距离另一辆车至少15米时,DistanceToBackCar才能工作。是否有其他替代方案?
编辑2:我在墙和街道中间使用了平面。当我查看物理调试可视化时,我从一侧看到了平面碰撞器,但从另一侧没有看到。我是Unity的新手,所以这可能是问题所在。
编辑3:我在街道中央添加了盒式碰撞器,DistanceToLeftSideOfMOTS开始工作了,但我试图使用墙来实现,但失败了。
编辑4:我将盒式碰撞器变大后就可以正常工作了。唯一的问题现在是汽车。

请注意,您在不同的Physics.Raycast调用中使用了不同的图层掩码。这是否与您的问题有关? - user2819245
@elgonzo我不认为这是问题,因为DistanceToRightSideOfMOTS可用,而DistanceToLeftSideOfMOTS却无法使用,即使它们都使用相同的层掩码:( - Vincent Quirion
只是一个小建议:我更喜欢使用一些LayerMask字段来配置射线的层,例如public LayerMask WallLayers;。然后你可以在检查器中简单地选择相应的层,并像这样使用它:Physics.Raycast(transform.position, transform.TransformDirection(Vector3.left), out hit, 25, WallLayers) - derHugo
1个回答

4

我建立了一个样例场景来尝试你的代码,但是没有发现任何问题。请确保你的车物体方向正确,并且墙壁和车辆都分配了适当的层和碰撞器。Unity的物理调试可视化可能会有所帮助。

enter image description here

另外,保持一定的DRY也是个好主意。例如,您可以将所有射线投射调用移动到单个方法中,以减少重复。这样,如果出现问题,需要查找的地方就会更少:
private void FixedUpdate()
{
    RequestDecision();
    RequestAction();
    UpdateWallDistances();
}

private void UpdateWallDistances()
{
    int leftWallMask = 1 << 11;
    int rightWallMask = 1 << 12;
    int wallMask = leftWallMask | rightWallMask;
    int carMask = 1 << 13;
    int middleOfStreetMask = 1 << 14;

    // Get the distances to the walls
    DistanceToLeftWall = GetDistance(Vector3.left, 25, leftWallMask, Color.red);
    DistanceToRightWall = GetDistance(Vector3.right, 25, rightWallMask, Color.red);
    DistanceToFrontWall = GetDistance(Vector3.forward, 50, wallMask, Color.red);
    DistanceToBackWall = GetDistance(Vector3.back, 50, wallMask, Color.red);

    // Get the distance to other cars
    DistanceToLeftCar = GetDistance(Vector3.left, 25, carMask, Color.green);
    DistanceToRightCar = GetDistance(Vector3.right, 25, carMask, Color.green);
    DistanceToFrontCar = GetDistance(Vector3.forward, 50, carMask, Color.green);
    DistanceToBackCar = GetDistance(Vector3.back, 50, carMask, Color.green);

    //Get distances to the middle of the street
    DistanceToLeftSideOfMOTS = GetDistance(Vector3.left, 10, middleOfStreetMask, Color.blue);
    DistanceToRightSideOfMOTS = GetDistance(Vector3.right, 10, middleOfStreetMask, Color.blue);
}

private float GetDistance(Vector3 direction, float maxDistance, int layerMask, Color debugColor)
{
    RaycastHit hit;
    if (Physics.Raycast(transform.position, transform.TransformDirection(direction), out hit, maxDistance, layerMask))
    {
        Debug.DrawRay(transform.position, transform.TransformDirection(direction) * hit.distance, debugColor);
        return hit.distance / maxDistance;
    }
    else
    {
        return 1;
    }
}

我尝试了你的代码,但它和我的做的一样。我不认为我的碰撞器和层掩码是问题所在,因为DistanceToBackWall工作正常,但DistanceToFrontWall甚至如果它们具有相同的层掩码(并且它们应该与相同的物体发生碰撞)。然而,我使用平面作为墙和街道的中心。当我查看Physics Debug Visualization时,我从一侧看到了平面碰撞器,但从另一侧没有看到。我是Unity新手,你觉得这可能是问题吗? - Vincent Quirion
另外,“确保您的汽车对象正确定位”是什么意思? - Vincent Quirion
我的意思是,您必须确保脚本所附加的对象朝向正确,这样raycast才能以你想要的方向和位置发射。 您可以添加其他的调试线来可视化raycast的方向。是的,平面的网格碰撞器只能被从一侧发射的raycast命中。如果您希望该对象可以从任何一侧被命中,则可以添加一个盒子碰撞器。 - Tobias K.
1
谢谢,我的问题出在碰撞器上,物理调试可视化确实帮了我很多。 - Vincent Quirion

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