我需要检查两条线是否相交。目前,这些包裹在边缘碰撞器中。
在我的最小示例中,我使用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);
}
}
}
这是我设置场景的方式:
如您在图片中所见,两行清晰地相交。
问题是没有任何内容输出到控制台。
对于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);
}
}
}
什么都没有。即使我计算出的点与对撞机完全对齐:
我为此进行了数学计算,但似乎工作正常,未经全面测试。如果在对撞机四处移动时运行相交检查,则会有点断断续续:
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;
}
}
但是我真的很想使用统一提供的东西。
答案 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)
您可以得到以下近似值:
您可以创建一个脚本,该脚本沿直线均匀添加多个小盒子碰撞器,效果越好。然后只需执行正常的碰撞检测。但是框越多(精度越高),计算方式就越昂贵。