Проверьте, пересекаются ли две линии - PullRequest
0 голосов
/ 10 октября 2018

Мне нужно проверить, пересекаются ли две линии.Они в настоящее время обернуты в краевые коллайдеры.

В моем минимальном примере я использую 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

Как видно на рисунке выше, две линии четко пересекаются.

Проблема в том, что на консоль ничего не выводится.

Я не уверен на 100% о том, как ContactFilter должен быть настроен, но, глядя на документацию, он используется для фильтрации результатов.Таким образом, оставляя это поле пустым, нужно включить все.

Мне действительно нужно сделать проверку между двумя строками.Поэтому функция, которая принимает их в качестве аргументов и возвращает логическое значение, указывающее на пересечение, была бы наиболее удобной.К сожалению, я не смог найти такую ​​функцию в 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 голосов
/ 12 октября 2018

Я понял, что могу заменить один из краевых коллайдеров на многоугольный коллайдер для моего случая использования.

Использование многоугольника и краевого коллайдера с Collider2D.OverlapsCollider() работает как положено.

Я не знаю, должен ли я принять это как ответ или нет, потому что это не решает первоначальный вопрос о нахождении функции в единстве для пересечения линии.

0 голосов
/ 12 октября 2018

Вы можете получить относительно близкое приближение с помощью следующего:

Вы можете создать скрипт, который равномерно добавляет несколько маленьких коллайдеров вдоль линии, чем больше, тем лучше.А затем просто выполните обычное обнаружение столкновений.Но чем больше блоков (более высокая точность), тем дороже затраты на вычисления.

0 голосов
/ 10 октября 2018

Используйте Collider.bounds.Intersects(Collider.bounds), чтобы определить, пересекаются ли две границы:

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

Это, к сожалению, не даст вам знать, пересекаются ли края.Однако, если это проверяет false, вы можете пропустить проверку ребер.

...