一种解决方案是搜索与碰撞点最接近的线对的点。所以基本上,我们希望多边形上的 CollisionEnter2D 函数看起来像这样:
private void OnCollisionEnter2D(Collision2D collision)
{
Vector2 contactPoint = collision.GetContact(0).point;
(Vector2, Vector2) closestLine = FindClosestLine(contactPoint);
if (closestLine != null)
print(closestLine);
}
我的解决方案可以用下图来描述:
(请见谅,我是程序员)。
作为一种伪算法:
define point = collisionPoint;
define pair;
define minDistance;
for pair := (p1, p2) in collider.points:
if (dist := shortestDistance(point, pair) < minDistance):
minDistance = dist
pair = (p1, p2)
在这个循环结束时,我们将得到我们正在寻找的两个点。这是我想出的一个粗略的实现:
private (Vector2, Vector2)? FindClosestLine(Vector2 contactPoint)
{
var localScale = transform.localScale;
var points = polygonCollider.points;
(Vector2, Vector2) closestLine = (default, default);
var shortestDistance = float.MaxValue;
for (var i = 1; i < points.Length; i++)
{
// We multiply the points by localScale, because the collider
// scales them to 1 internally, regardless of our size.
var line = (points[i - 1] * localScale, points[i] * localScale);
var distance = MinDistPointToLine(contactPoint, line);
if (distance < shortestDistance)
{
shortestDistance = distance;
closestLine = line;
}
}
if (shortestDistance < float.MaxValue)
return closestLine;
else return null;
}
为了算出最短距离,我们可以使用一些基本的三角学(再次请原谅画图。)
代码如下所示:
private static float MinDistPointToLine(Vector2 point, (Vector2, Vector2) line)
{
// Calculate the shortest distance between the line (p[n+1] - p[n]) and the given point.
var (end, start) = line;
var lineLength = (start - end).magnitude;
var lineLengthSqr = lineLength * lineLength;
var distToStartSqr = (point - end).sqrMagnitude;
var distToEndSqr = (point - start).sqrMagnitude;
// Equation found by algebra.
return distToStartSqr - (distToStartSqr - distToEndSqr - lineLengthSqr) / 2 * lineLength;
}
在这种情况下,我们只是打印两个点,但您显然会使用它们来实现您描述的算法。