Unity中检测矩形和圆形是否相交

游戏制作中经常需要各种形状的相交检测,那么如何检测一个圆形和矩形是否相交呢?

答案是用BoxCollider和SphereCollider~

慢着,如果不想用物理引擎该怎么办呢?

可以使用代码进行相交检测,思路就是先把圆形转换到矩形的局部坐标系下,再判断圆形的上下左右四个点是否在矩形内,如果没有判断矩形四个顶点是否在圆形内。

下面扩展了Transform类的方法,用矩形的transform调用IsInSquareRange方法,传入相应的参数就可。

注:

  1. 要求矩形的transform.position就是矩形的中心。
  2. 下面只计算了XZ平面上的相交,忽略了Y轴
	///获取点对物体的相对坐标,忽略缩放
    public static Vector3 GetRelativePosition(this Transform transform,Vector3 position)
    { 
        Vector3 vector = position - transform.position;
        Vector3 relativePosition = Vector3.zero;
        relativePosition.x = Vector3.Dot(vector, transform.right.normalized);
        relativePosition.y = Vector3.Dot(vector, transform.up.normalized);
        relativePosition.z = Vector3.Dot(vector, transform.forward.normalized);
        return relativePosition;
    }

    private static bool IsPointInSquareRange(Vector2 halfSize, float posX, float posZ)
    { 
        return Mathf.Abs(posX) <= halfSize.x && Mathf.Abs(posZ) <= halfSize.y;
    }

    ///获取矩形四角点的世界坐标
    public static Vector3[] GetSquareCorners(this Transform transform, float sizeX, float sizeZ)
    { 
        sizeX = sizeX / 2;
        sizeZ = sizeZ / 2;
        var center = transform.localPosition;
        float rotation = transform.localEulerAngles.y;
        Vector3[] corners = new Vector3[4];
        corners[0] = new Vector3(-sizeX, 0, sizeZ);
        corners[1] = new Vector3(sizeX, 0, sizeZ);
        corners[2] = new Vector3(-sizeX, 0, -sizeZ);
        corners[3] = new Vector3(sizeX, 0, -sizeZ);

        var q = Quaternion.AngleAxis(rotation, Vector3.up);
        for (int i = 0; i < 4; i++)
        { 
            corners[i] = q * corners[i] + center;
        }
        return corners;
    }

    /// <summary>
    /// 检查圆中是否和矩形相交
    /// </summary>
    /// <param name="transform">矩形Transform</param>
    /// <param name="squareSize">矩形尺寸</param>
    /// <param name="center">圆中心坐标</param>
    /// <param name="radius">圆形半径</param>
    public static bool IsInSquareRange(this Transform transform, Vector2 squareSize, Vector3 center, float radius)
    { 
        var halfSize = squareSize/ 2;
        var localPos = transform.GetRelativePosition(center);
		
		//粗略计算最大范围,减少计算量
        if (localPos.sqrMagnitude > Mathf.Pow(radius + halfSize.x + halfSize.y, 2))
            return false;

        //圆的左右最近点
        var closePoint = localPos;
        var subValue = closePoint.x > 0 ? Mathf.Min(closePoint.x, radius) : Mathf.Max(closePoint.x, -radius);
        closePoint.x -= subValue;
        if (IsPointInSquareRange(halfSize, closePoint.x, closePoint.z))
            return true;

        //圆的上下最近点
        closePoint = localPos;
        subValue = closePoint.z > 0 ? Mathf.Min(closePoint.z, radius) : Mathf.Max(closePoint.z, -radius);
        closePoint.z -= subValue;
        if (IsPointInSquareRange(halfSize, closePoint.x, closePoint.z))
            return true;

        //检查矩形四角是否在圆内
        var corners = GetSquareCorners(transform, squareSize.x, squareSize.y);
        var len = corners.Length;
        float maxDistanceSqr = radius * radius;
        for (int i = 0; i < len; i++)
        { 
            var point = corners[i];
            if ((point - center).sqrMagnitude <= maxDistanceSqr)
                return true;
        }

        return false;
    }

    原文作者:弦余
    原文地址: https://blog.csdn.net/qq_18220673/article/details/125577356
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞