Unity2D/C#:如何让光线投射忽略它的第一次碰撞?

Unity2D/C#: How do I make a raycast ignore its first collision?

我的平台游戏的光线投射控制器的一个特点是玩家可以跳下单向平台。这很好用,但我想添加额外的功能,让玩家只有在他或她要跳到的平台在一定距离内时才能跳下去。

我的平台控制器的跳下功能是这样的:

  1. 我的角色从它的盒子对撞机下方发射一条射线,并检测它是否在地面上。
  2. 如果是,并且地面被标记为单向平台,并且玩家按下跳下按钮,它将跳下到下一个平台,无论距离多远。

我已经尝试制作一个跳下方法,从角色的盒子碰撞器的中心创建一个新的光线投射(下面的代码中没有显示,因为到目前为止我完全没有成功),并检查一个一定距离的碰撞。我的问题是它总是检测到它即将跳下的平台的碰撞器,而永远没有机会检测到任何其他东西。

我如何让这个新的光线投射忽略第一次碰撞,潜在地检测光线距离内的碰撞,如果碰撞到什么东西让我的角色跳下来?另外,我什至需要做一个新的光线投射,还是我可以只使用我控制器上的当前光线投射?

这是我的一些光线投射控制器脚本,希望能解释一些功能:

private void MoveVertically(ref Vector3 deltaMovement)
{
    float directionY = Mathf.Sign(deltaMovement.y);
    float rayLength = Mathf.Abs(deltaMovement.y) + skinWidth;

    for (int i = 0; i < verticalRayCount; i++)
    {
        Vector2 rayOrigin = (directionY == -1) ? raycastOrigins.bottomLeft : raycastOrigins.topLeft;
        rayOrigin += Vector2.right * (verticalRaySpacing * i + deltaMovement.x);

        RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.up * directionY, rayLength, collisionMask);

        Debug.DrawRay(rayOrigin, Vector2.up * directionY * rayLength, Color.red);

        if (hit)
        {
            if (hit.collider.tag == "platformOneWay")
            {
                if (directionY == 1)
                {
                    State.IsCollidingWithOneWay = true;
                    State.IsCollidingAbove = false;
                    continue;
                }

                if (CanJumpDown)
                {
                    State.IsCollidingBelow = false;
                    continue;
                }
            }

            deltaMovement.y = (hit.distance - skinWidth) * directionY;
            rayLength = hit.distance;

实际上,Unity3D提供了一个API,叫做Physics2D.RaycastAll,returns不仅是第一个光线投射命中,而且是最大距离内的所有光线投射命中。
Physics2D.RaycastAll 以两个 Vector2 作为参数(光线投射原点和方向)和 returns 一个 RaycastHit2D 的数组,它按从原点到命中点的距离排序。
下面是一段代码,向您展示了此函数的作用:

public class Raycaster : MonoBehaviour
{
    private void Start()
    {
        RaycastHit2D[] hits = Physics2D.RaycastAll(transform.position, Vector2.down);
        for (int i = 0; i < hits.Length; ++i)
        {
            Debug.LogFormat("The name of collider {0} is \"{1}\".", 
                i, hits[i].collider.gameObject.name);
        }
    }
}

另一种方法是创建 LayerMasks。在 Unity 编辑器中创建一个新层并将该层分配给您的对撞机所在的游戏对象。

使用 LayerMask.GetMask 在您的代码中获取图层蒙版 ID,并将其添加为参数。现在你的 Raycast 将只投射分配给图层的碰撞体。

var layerMask = LayerMask.GetMask ("myLayerName");
var ray = Camera.main.ScreenPointToRay (Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast (ray, out hit, 100.0f, layerMask)) {
    Debug.Log ("Got ya!");
}