当たり判定やろう
球とAABBの当たり判定
ゲームの当たり判定では、複雑なモデルをそのまま比較するのではなく、扱いやすい形で近似して判定することがあります。
代表的な形が 球(Sphere) と AABB です。
1.球と球の当たり判定
球は、中心と半径で表せます。

2つの球がちょうど接するとき、中心間距離 (d) は半径の合計と等しくなります。
$$ d=r_A+r_B $$
したがって、
$$ d\leq r_A+r_B $$
なら、2つの球は接触または重なっています。
当たり判定では平方根を求めず、
$$ d^2\leq(r_A+r_B)^2 $$
を比較できます。
struct Sphere
{
Vector3 center;
float radius;
};
bool IsHit(const Sphere& a, const Sphere& b)
{
Vector3 diff = b.center - a.center;
float distanceSq =
diff.x * diff.x +
diff.y * diff.y +
diff.z * diff.z;
float radiusSum = a.radius + b.radius;
return distanceSq <= radiusSum * radiusSum;
}
2.AABB
AABBは Axis-Aligned Bounding Box の略です。
まず2次元で min と max の意味を見ます。

3次元ではZ方向が追加されます。

AABBは、
$$ \mathrm{min}=(x_{min},y_{min},z_{min}) $$
$$ \mathrm{max}=(x_{max},y_{max},z_{max}) $$
で表せます。
3.AABBとAABBの当たり判定
2次元では、X方向とY方向の両方で区間が重なれば矩形どうしが重なっています。

3次元ではZ方向も調べます。

X、Y、Zのどれか1方向でも完全に離れていれば、2つのAABBは衝突していません。
struct AABB
{
Vector3 min;
Vector3 max;
};
bool IsHit(const AABB& a, const AABB& b)
{
if (a.max.x < b.min.x || a.min.x > b.max.x)
{
return false;
}
if (a.max.y < b.min.y || a.min.y > b.max.y)
{
return false;
}
if (a.max.z < b.min.z || a.min.z > b.max.z)
{
return false;
}
return true;
}
4.球とAABBの当たり判定
球とAABBでは形が違うため、中心どうしの距離だけでは判定できません。
AABB上で、球の中心に最も近い点を求めます。
その点を最近点 (Q)、球の中心を (C) とします。

最近点 (Q) が分かれば、
$$ |C-Q| $$
は球の中心からAABBまでの最短距離になります。
5.clampで最近点を求める
clamp は、値を指定した区間の中へ収める処理です。

X座標とY座標を別々にclampすると、2次元AABB上の最近点を求められます。

3次元ではZ座標も同じように計算します。
$$ Q_x=\mathrm{clamp}(C_x,x_{min},x_{max}) $$
$$ Q_y=\mathrm{clamp}(C_y,y_{min},y_{max}) $$
$$ Q_z=\mathrm{clamp}(C_z,z_{min},z_{max}) $$
6.最近点のできる場所
球の中心の位置によって、最近点のできる場所は変わります。


面・側面・角・内部を別々の式で処理する必要はありません。
各成分を clamp すれば、同じ方法で最近点を求められます。
7.球とAABBの判定式
最近点 (Q) が求まったら、
$$ \mathbf{v}=C-Q $$
を作ります。

衝突条件は、
$$ |\mathbf{v}|^2\leq r^2 $$
です。
bool IsHit(const Sphere& sphere, const AABB& box)
{
Vector3 closest;
closest.x = std::clamp(
sphere.center.x,
box.min.x,
box.max.x);
closest.y = std::clamp(
sphere.center.y,
box.min.y,
box.max.y);
closest.z = std::clamp(
sphere.center.z,
box.min.z,
box.max.z);
Vector3 diff = sphere.center - closest;
float distanceSq =
diff.x * diff.x +
diff.y * diff.y +
diff.z * diff.z;
return distanceSq <= sphere.radius * sphere.radius;
}
8.3種類の判定を整理する

| 判定 | 調べるもの | 数学的な考え方 |
|---|---|---|
| 球 vs 球 | 中心間距離 | 2点間の距離 |
| AABB vs AABB | X・Y・Z方向の範囲 | 区間の重なり |
| 球 vs AABB | 球中心と最近点の距離 | clamp+2点間の距離 |