SionGames 技術Blog

C#やUnityを触っているサーバープログラマーが色々と書いていく所

ゲームで使う円と球の当たり判定

ゲームで当たり判定を行いたい時の手軽な判定方法の一つに
円や球の当たり判定があります。
Unityではその辺りの計算を知らなくてもゲームエンジン側で
当たり判定の仕組みが用意されていますが、
自分で計算を知っておくと役に立つ事もあります。
(サーバー側で当たり判定を実装する必要が出た時とか)

2点間の距離の公式


この公式は今回の円と球の当たり判定の両方に使用する数学の公式になります。
2次元座標系
距離 =  \sqrt{ ( ax-bx ) ^2 + ( ay-by ) ^2 }
3次元座標系
距離 =  \sqrt{ ( ax-bx ) ^2 + ( ay-by ) ^2 + ( az-bz ) ^2 }

C#ソースコード的にはこのようになります。
2次元座標系

float xDis = x2 - x1;
float yDis = y2 - y1;
double distance = Math.sqrt((xDis * xDis) + (yDis * yDis));

3次元座標系

float xDis = x2 - x1;
float yDis = y2 - y1;
float zDis = z2 - z1;
double distance = Math.sqrt((xDis * xDis) + (yDis * yDis) + (zDis * zDis));

円の当たり判定


円の当たり判定は、2つの円の距離を上記の公式で求める必要があります。
円Aの中心座標が(1, 1)
円Bの中心座標が(3, 3)だったとすると
距離 =  \sqrt{ ( 1-3 ) ^2 + ( 1-3 ) ^2 }
距離 =  \sqrt{ 8 }
距離 =  2\sqrt{ 2 }
距離 ≒ 2.828
ということは、円Aの半径+円Bの半径の和が2.828以上であれば
二つの円は重なっていると判定できます。

f:id:SionGames:20190713150743p:plain
半径1の円が(1,1)と(3,3)にあるときの図

球の当たり判定


球の当たり判定は円の当たり判定にz軸を追加するだけです。 球Aの中心座標が(1, 1, 1)
球Bの中心座標が(3, 3, 3)だったとすると
距離 =  \sqrt{ ( 1-3 ) ^2 + ( 1-3 ) ^2 + ( 1-3 ) ^2 }
距離 =  \sqrt{ 12 }
距離 =  3\sqrt{ 2 }
距離 ≒ 3.464
ということで、球Aの半径+球Bの半径の和が3.464以上であれば
二つの球は重なっていると判定できます。

処理負荷軽減


上で説明した方法で当たり判定は実装できるのですが、
Math.sqrt()は少々負荷がかかる処理です。
円や球の距離が不要かつ重なっているかだけ判定したい場合は
Math.sqrt()無しで処理を記述する事が出来ます。

float radius = A半径 + B半径;
float xDis = x2 - x1;
float yDis = y2 - y1;
float distanceSquare = ( xDis * xDis ) + ( yDis * yDis );
bool isHit = ( radius * radius ) > distanceSquare;

処理負荷の高いシステムではこのような最適化も活用したいです。