Reputation: 1026
I need to check if two lines intersect. These are currently wrapped in edge colliders.
In my minimal example i using 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);
}
}
}
This is how i have set up my scene:
As you can see in the picture above the two lines clearly intersect.
The issue is that nothing is outputed to the console.
I am not 100% sure about how ContactFilter
should be configured but looking at the documentation it is used for filtering out results. So leaving it blank should include everything.
I really only need to do the check between two lines. So a function that takes them as arguments and returns a bool indicating intersection would be most convenient. Unfortunetaly I could not find such function in Unity.
It should not be overly complicated to construct the function myself but i would prefer to use the functions unity provide as much as possible. So consider this more of a unity related question than a math related one.
EDIT:
Using Collider2D.IsTouching(Collider2D)
does not seem to work either. I use the same setup as before with this code instead:
public class EdgeColliderChecker : MonoBehaviour
{
public EdgeCollider2D e1;
public EdgeCollider2D e2;
void Update () {
if (e1.IsTouching(e2)) {
Debug.Log("INTERSECTION");
}
}
}
Edit 2:
I tried creating my own method for this:
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);
}
}
}
Still nothing. Even though the points i calculate align perfectly with the collider:
I did the math for it and it seems to work ok, not tested very thorougly. The intersection check is a bit choppy if it is run while the colliders are moving around:
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;
}
}
But I'd really like to use something provided by unity instead.
Upvotes: 0
Views: 2270
Reputation: 3861
You could get a relatively close approximation with the following:
You could create a script that adds several small box colliders evenly along the line, the more the better. And then just do normal collision detection. But the more boxes (higher precision), the more costly computation-wise.
Upvotes: 1
Reputation: 1026
I realized that i could exhange one of the edge colliders for a polygon collider for my use case.
Using a polygon and an edge collider with Collider2D.OverlapsCollider()
works as expected.
I don't know if i should accept this as an answer or not because it does not solve the original question about finding a funciton in unity for line intersection.
Upvotes: 1
Reputation: 20270
Use Collider.bounds.Intersects(Collider.bounds)
to determine if two bounds are intersecting:
void Update () {
if (e1.bounds.Intersects(e2.bounds)) {
Debug.Log("Bounds intersecting");
}
}
This unfortunately won't let you know if the edges are intersecting. However, if this tests false, you can skip testing the edges.
Upvotes: 1