简介
圆与 AABB 进行碰撞检测,实质可以化为一个点与 AABB 进行检测,然后根据检测结果与圆的半径进行比较。
原理
二维
首先我们把圆与 AABB 的问题化为点与 AABB 的问题。
从一个点到一条直线的最短距离,就是从这个点做一条垂线,这样我们就得到了一个点 P。
如图所示,在 Y 轴上,这个点的 Y 坐标在矩形 Y 坐标的最大值和最小值之间。这时我们观察图像可知,P 点的 Y 坐标就是圆心的 Y 坐标。
在 X 轴上,这个点的 X 坐标在矩形 X 坐标的最大值和最小值之外。由于 P 点是矩形上一点,因此 P 的 X 坐标一定限制在矩形的 X 坐标之内。所以,此时 P 点的 X 坐标为矩形的 X 坐标最小值。
通过这两条我们不难看出,一个点在 AABB 的最近点坐标一定在 AABB 最大最小坐标之内,如果超出的话就设置为 AABB 的最大或最小坐标。
当我们得到 P 点坐标之后,就可以通过圆心和 P 点求出这两个点之间的距离。然后我们只需要比较这个距离和圆半径的关系就可以知道这两个物体是否相交。
三维
在三维空间中,两个对象碰撞检测的原理和二维空间一样,只不过多加了一个 Z 轴。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| using System.Collections; using System.Collections.Generic; using UnityEngine;
public class CollisionData : MonoBehaviour { public Vector3 max = Vector3.zero; public Vector3 min = Vector3.zero; public Vector3 center = Vector3.zero; public float radius = 1.0f; } ---------------------------------------------
private bool CollisionCircle2AABB(CollisionData data1,CollisionData data2) { Vector3 center = data1.center; Vector3 nearP = GetClosestPointAABB(data1,data2); float distance = (nearP - center).sqrMagnitude; float radius = Mathf.Pow(data1.radius, 2); if (distance <= radius) { return true; } return false; }
private Vector3 GetClosestPointAABB(CollisionData data1,CollisionData data2) { Vector3 center = data1.center; Vector3 nearP = Vector3.zero; nearP.x = Mathf.Clamp(center.x, data2.min.x, data2.max.x); nearP.y = Mathf.Clamp(center.y, data2.min.y, data2.max.y); nearP.z = Mathf.Clamp(center.z, data2.min.z, data2.max.z); return nearP; }
|
其他
和圆与圆的检测一样,圆与 AABB 检测求两点距离的时候也使用平方来计算,减少开方的性能消耗。
碰撞检测示例工程