检查两条线是否相交

时间:2018-10-10 18:25:34

标签: c# unity3d math collision-detection collision

我需要检查两条线是否相交。目前,这些包裹在边缘碰撞器中。

在我的最小示例中,我使用Collider2D.OverlapsCollider

public class EdgeColliderChecker : MonoBehaviour
{
    public EdgeCollider2D e1;
    public EdgeCollider2D e2;

    void Update () {
        Collider2D[] results1 = new Collider2D[1];
        e1.OverlapCollider(new ContactFilter2D(), results1);
        if (results1[0] != null)
        {
            Debug.Log(results1[0].name);
        }

        Collider2D[] results2 = new Collider2D[1];
        e1.OverlapCollider(new ContactFilter2D(), results2);
        if (results2[0] != null) {
            Debug.Log(results2[0].name);
        }
    }
}

这是我设置场景的方式:

scene setup

如您在图片中所见,两行清晰地相交。

问题是没有任何内容输出到控制台。

对于ContactFilter的配置方式,我不是100%不确定,但是请查看用于过滤结果的文档。因此,将其保留为空白应包括所有内容。

我真的只需要在两行之间进行检查。因此,将它们作为参数并返回布尔值指示交集的函数将是最方便的。不幸的是,我在Unity中找不到这样的功能。

自己构造函数应该不会太复杂,但是我宁愿使用unity提供的尽可能多的函数。因此,与数学相关的问题,应更多地考虑这是一个与团结相关的问题。

编辑:

使用Collider2D.IsTouching(Collider2D)似乎也不起作用。我使用与此代码相同的设置:

public class EdgeColliderChecker : MonoBehaviour
{
    public EdgeCollider2D e1;
    public EdgeCollider2D e2;

    void Update () {
        if (e1.IsTouching(e2)) {
            Debug.Log("INTERSECTION");
        }
    }
}

编辑2:

我尝试为此创建自己的方法:

public static class EdgeColliderExtentions {
    public static List<Collider2D> GetInterSections(this EdgeCollider2D collider)
    {
        List<Collider2D> intersections = new List<Collider2D>();
        Vector2[] points = collider.points;
        for (int i = 0; i < points.Length - 1; i++)
        {
            Vector2 curr = collider.transform.TransformPoint(points[i]);
            Vector2 next = collider.transform.TransformPoint(points[i + 1]);
            Vector2 diff = next - curr;

            Vector2 dir = diff.normalized;

            float distance = diff.magnitude;

            RaycastHit2D[] results = new RaycastHit2D[30];
            ContactFilter2D filter = new ContactFilter2D();

            Debug.DrawLine(curr, curr + dir * distance, Color.red, 1 / 60f);

            int hits = Physics2D.Raycast(curr, dir, filter, results, distance);

            for (int j = 0; i < hits; i++)
            {
                Collider2D intersection = results[j].collider;
                if (intersection != collider)
                {
                    intersections.Add(intersection);
                }
            }
        }
        return intersections;
    }
}

EdgeColliderChecker

public class EdgeColliderChecker : MonoBehaviour
{
    public EdgeCollider2D e1;

    void Update ()
    {
        List<Collider2D> hits = e1.GetInterSections();
        if (hits.Count > 0) {
            Debug.Log(hits.Count);
        }
    }
}

什么都没有。即使我计算出的点与对撞机完全对齐:

enter image description here

我为此进行了数学计算,但似乎工作正常,未经全面测试。如果在对撞机四处移动时运行相交检查,则会有点断断续续:

public class Line {
    private Vector2 start;
    private Vector2 end;

    public Line(Vector2 start, Vector2 end)
    {
        this.start = start;
        this.end = end;
    }

    public static Vector2 GetIntersectionPoint(Line a, Line b)
    {
        //y = kx + m;
        //k = (y2 - y1) / (x2 - x1)
        float kA = (a.end.y - a.start.y) / (a.end.x - a.start.x);
        float kB = (b.end.y - b.start.y) / (b.end.x - b.start.x);

        //m = y - k * x
        float mA = a.start.y - kA * a.start.x;
        float mB = b.start.y - kB * b.start.x;

        float x = (mB - mA) / (kA - kB);
        float y = kA * x + mA;
        return new Vector2(x,y);
    }

    public static bool Intersects(Line a, Line b)
    {
        Vector2 intersect = GetIntersectionPoint(a, b);            

        if (Vector2.Distance(a.start, intersect) < Vector2.Distance(a.start, a.end) &&
            Vector2.Distance(a.end, intersect) < Vector2.Distance(a.start, a.end))
        {
            return true;
        }
        return false;
    }
}

public static class EdgeColliderExtentions
{
    public static bool Intersects(this EdgeCollider2D collider, EdgeCollider2D other)
    {
        Vector2[] points = collider.points;
        Vector2[] otherPoints = other.points;
        for (int i = 0; i < points.Length - 1; i++)
        {
            Vector2 start = collider.transform.TransformPoint(points[i]);
            Vector2 end = collider.transform.TransformPoint(points[i + 1]);
            Line line = new Line(start, end);
            for (int j = 0; j < otherPoints.Length - 1; j++)
            {
                Vector2 otherStart = other.transform.TransformPoint(otherPoints[i]);
                Vector2 otherEnd = other.transform.TransformPoint(otherPoints[i + 1]);
                Line otherLine = new Line(otherStart, otherEnd);
                if (Line.Intersects(line, otherLine))
                {
                    return true;
                }
            }
        }
        return false;
    }
}

但是我真的很想使用统一提供的东西。

3 个答案:

答案 0 :(得分:1)

使用Collider.bounds.Intersects(Collider.bounds)确定两个边界是否相交:

void Update () {
    if (e1.bounds.Intersects(e2.bounds)) {
        Debug.Log("Bounds intersecting");
    }
}

不幸的是,这不会让您知道边缘是否相交。但是,如果此测试为假,则可以跳过对边缘的测试。

答案 1 :(得分:1)

我意识到我可以为我的用例更换一个多边形对撞机的边缘对撞机。

Collider2D.OverlapsCollider()一起使用多边形和边缘碰撞器可以正常工作。

我不知道我是否应该接受这个答案,因为它不能解决有关为线相交找到统一的函子的原始问题。

答案 2 :(得分:1)

您可以得到以下近似值:

您可以创建一个脚本,该脚本沿直线均匀添加多个小盒子碰撞器,效果越好。然后只需执行正常的碰撞检测。但是框越多(精度越高),计算方式就越昂贵。