Unity实现图形相交检测

2020-04-28 20:01:44王振洲

圆形与凸多边形

定义多边形:

/// <summary>
/// 多边形区域。
/// </summary>
public struct PolygonArea
 {
  public Vector2[] vertexes;
 }

相交检测:

/// <summary>
/// 判断多边形与圆形相交
/// </summary>
/// <param name="polygonArea"></param>
/// <param name="target"></param>
/// <returns></returns>
public static bool PolygonS(PolygonArea polygonArea, CircleArea target)
  {
   if (polygonArea.vertexes.Length < 3)
   {
    Debug.Log("多边形边数小于3.");
    return false;
   }
   #region 定义临时变量
   //圆心
   Vector2 circleCenter = target.o;
   //半径的平方
   float sqrR = target.r * target.r;
   //多边形顶点
   Vector2[] polygonVertexes = polygonArea.vertexes;
   //圆心指向顶点的向量数组
   Vector2[] directionBetweenCenterAndVertexes = new Vector2[polygonArea.vertexes.Length];
   //多边形的边
   Vector2[] polygonEdges = new Vector2[polygonArea.vertexes.Length];
   for (int i = 0; i < polygonArea.vertexes.Length; i++)
   {
    directionBetweenCenterAndVertexes[i] = polygonVertexes[i] - circleCenter;
    polygonEdges[i] = polygonVertexes[i] - polygonVertexes[(i + 1)% polygonArea.vertexes.Length];
   }
   #endregion
 
   #region 以下为圆心处于多边形内的判断。
   //总夹角
   float totalAngle = Vector2.SignedAngle(directionBetweenCenterAndVertexes[polygonVertexes.Length - 1], directionBetweenCenterAndVertexes[0]);
   for (int i = 0; i < polygonVertexes.Length - 1; i++)
    totalAngle += Vector2.SignedAngle(directionBetweenCenterAndVertexes[i], directionBetweenCenterAndVertexes[i + 1]);
   if (Mathf.Abs(Mathf.Abs(totalAngle) - 360f) < 0.1f)
    return true;
   #endregion
   #region 以下为多边形的边与圆形相交的判断。
   for (int i = 0; i < polygonEdges.Length; i++)
    if (SegmentPointSqrDistance(polygonVertexes[i], polygonEdges[i], circleCenter) < sqrR)
     return true;
   #endregion
   return false;
  }

圆形与AABB

定义AABB:

/// <summary>
/// AABB区域
/// </summary>
public struct AABBArea
 {
  public Vector2 center;
  public Vector2 extents;
 }

AABB是凸多边形的特例,是长宽边分别与X/Y轴平行的矩形,这里我们要充分的利用他的对称性。

1 利用对称性将目标圆心映射到,以AABB中心为原点、两边为坐标轴的坐标系,的第一象限

2 将目标圆心映射到,以AABB第一象限角点为原点、两边为坐标轴的坐标系,的第一象限

3 最后只需要判断圆形半径与步骤2中映射点的向量大小

相交检测:

/// <summary>
/// 判断AABB与圆形相交
/// </summary>
/// <param name="aABBArea"></param>
/// <param name="target"></param>
/// <returns></returns>
public static bool AABB(AABBArea aABBArea, CircleArea target)
  {
   Vector2 v = Vector2.Max(aABBArea.center - target.o, -(aABBArea.center - target.o));
   Vector2 u = Vector2.Max(v - aABBArea.extents,Vector2.zero);
   return u.sqrMagnitude < target.r * target.r;
  }