2009年06月15日

回転する矩形と点の当たり判定

単純な2Dのゲームでは、XY軸と並行な矩形だけを扱います。そのような矩形と点の当たり判定というのは、単純な座標の大小関係で判定することができます。

if (x >= lelt && x <= right && y >= top && y <= bottom)
{
    // 矩形と点の衝突
}

しかし、ゲームに回転の要素が入ってくるとこのアプローチでは対応しきれなくなり、回転する矩形と点の当たり判定を処理する必要があります。

やり方は色々あるのですが、ベクトル大好きっ子の私としては、こういう問題はベクトル演算で解きたくなります。

まず、矩形の1点を基準とし、点Pまでの相対位置ベクトルをP、矩形の2辺のベクトルをそれぞれV1V2とします。また、V1V2の長さを1に正規化したベクトルをそれぞれN1N2とします。

回転する矩形と点P

ここでN1Pの内積は、N1に沿った線上に点Pから垂線を降ろしたときの長さと等しくなります。同様にN2Pの内積も、N2に沿った線上の長さになります。もし、点PがN1と逆方向にある場合は、内積の値は負の値になります。

よって、点Pが矩形内に含まれる条件は

0 ≦ N1P ≦ |V1| かつ 0 ≦ N2P ≦ |V2|

となります。

ちなみに、この不等式の両辺をそれぞれ|V1|、|V2|で割ると

0 ≦ N1P÷|V1| ≦ 1  (以下V2の式は省略)

ここでN1=V1÷|V1|なので

0 ≦ V1P÷|V1|^2 ≦ 1

また、|V1|^2=V1V1なので

0 ≦ (V1P)÷(V1V1) ≦ 1

となります。(^2は2乗を表します)

|V1|やN1の計算には平方根が必要ですが、この形に変形すると平方根が消えて、内積(加算と乗算)と除算だけになります。こちらの方が計算が軽いですし、式も分かりやすくて良いと思います。条件式が定数になるので、最適化も効きそうです。ただし、|V1|が0になると0除算エラーになるので注意してください。

今回は矩形の角を基準にしましたが、中心を基準にする場合は

-1 ≦ (V1P)÷(V1V1) ≦ 1

となり、更にabs()を利用すると

abs((V1P)÷(V1V1)) ≦ 1

となります。(V1は中心から辺までのベクトルで、上図のV1の半分の長さになります)

今回の方法は、V1V2が直行していないといけないことを忘れないでください。並行四辺形のような歪んだ四角形では使えません。

確認のために、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メソッドを利用すると簡単にできます。

タグ:代数幾何
2009年06月15日 【プログラミング】 | コメント(0) |

この記事へのトラックバックURL


この記事へのトラックバック
この記事へのコメント

コメントを書く
お名前: [必須入力]

メールアドレス:

ホームページアドレス:

コメント: [必須入力]

認証コード: [必須入力]


※画像の中の文字を半角で入力してください。
×

この広告は1年以上新しい記事の投稿がないブログに表示されております。