単純な2Dのゲームでは、XY軸と並行な矩形だけを扱います。そのような矩形と点の当たり判定というのは、単純な座標の大小関係で判定することができます。
if (x >= lelt && x <= right && y >= top && y <= bottom) { // 矩形と点の衝突 }
しかし、ゲームに回転の要素が入ってくるとこのアプローチでは対応しきれなくなり、回転する矩形と点の当たり判定を処理する必要があります。
やり方は色々あるのですが、ベクトル大好きっ子の私としては、こういう問題はベクトル演算で解きたくなります。
まず、矩形の1点を基準とし、点Pまでの相対位置ベクトルをP、矩形の2辺のベクトルをそれぞれV1、V2とします。また、V1とV2の長さを1に正規化したベクトルをそれぞれN1、N2とします。
ここでN1とPの内積は、N1に沿った線上に点Pから垂線を降ろしたときの長さと等しくなります。同様にN2とPの内積も、N2に沿った線上の長さになります。もし、点PがN1と逆方向にある場合は、内積の値は負の値になります。
よって、点Pが矩形内に含まれる条件は
0 ≦ N1・P ≦ |V1| かつ 0 ≦ N2・P ≦ |V2|
となります。
ちなみに、この不等式の両辺をそれぞれ|V1|、|V2|で割ると
0 ≦ N1・P÷|V1| ≦ 1 (以下V2の式は省略)
ここでN1=V1÷|V1|なので
0 ≦ V1・P÷|V1|^2 ≦ 1
また、|V1|^2=V1・V1なので
0 ≦ (V1・P)÷(V1・V1) ≦ 1
となります。(^2は2乗を表します)
|V1|やN1の計算には平方根が必要ですが、この形に変形すると平方根が消えて、内積(加算と乗算)と除算だけになります。こちらの方が計算が軽いですし、式も分かりやすくて良いと思います。条件式が定数になるので、最適化も効きそうです。ただし、|V1|が0になると0除算エラーになるので注意してください。
今回は矩形の角を基準にしましたが、中心を基準にする場合は
-1 ≦ (V1・P)÷(V1・V1) ≦ 1
となり、更にabs()を利用すると
abs((V1・P)÷(V1・V1)) ≦ 1
となります。(V1は中心から辺までのベクトルで、上図のV1の半分の長さになります)
今回の方法は、V1とV2が直行していないといけないことを忘れないでください。並行四辺形のような歪んだ四角形では使えません。
確認のために、Silverlightでデモを作ってみました。
回転している青い矩形にマウスカーソルが重なると赤くなります。
当たり判定部分のソースコードは次のようになっています。
for (int i = 0; i < 6; ++i) { Rotator o = rotator[i]; Vector2 vp = MousePt - o.Pos; Double d1 = (o.V1 * vp) / (o.V1 * o.V1); Double d2 = (o.V2 * vp) / (o.V2 * o.V2); if (d1 >= 0.0 && d1 <= 1.0 && d2 > 0 && d2 < 1.0) { o.shape.Fill = new SolidColorBrush(Colors.Red); } }
ちなみに、Silverlightでこのような描画オブジェクトとの当たり判定を行う場合は、わざわざ自分で計算しなくてもVisualTreeHelperクラスのFindElementsInHostCoordinatesメソッドを利用すると簡単にできます。

