直線と矩形の衝突
ここでは直線と矩形(回転なし)の衝突判定についてまとめます。
考え方
直線と矩形の衝突について、直線と矩形の4辺のいずれかが当たっていれば直線と矩形は当たっているとしても良さそうと思ったのですが
直線と矩形が当たっているかどうかだけであれば、矩形の角4つ全てが、直線の右側にある、もしくは左側にあるとしても判定ができそうです。
前者の場合、直線と線分の衝突を判定する事になりますが
後者の場合、直線と点の判定だけでよく、計算コストも安くすみそうなので、後者の方法で判定していきたいと思います。
求め方
矩形の角4点はただの点ですので、直線と点の関係を調べる問題に帰結します。
ある点が直線の右にあるのか、左にあるのか、はたまた直線上にあるのかはベクトルの外積の特性を使って調べる事ができます。
直線の方向ベクトルを $\vec{v_{1}}$、直線上の点から矩形の角に向かうベクトルを $\vec{v_{2}}$ とします。
$\vec{v_{1}}$ と $\vec{v_{2}}$ の外積を取り、結果がプラスなら角は直線の左側に、マイナスなら直線の右側に、0であれば直線上にあることになります。
$\vec{v_{1}} \times \vec{v_{2}} > 0$ であれば角は直線の左側
$\vec{v_{1}} \times \vec{v_{2}} < 0$ であれば角は直線の右側
$\vec{v_{1}} \times \vec{v_{2}} = 0$ であれば角は直線上
上記の判定を矩形の角4点全てに対して行っていきます。
直線と矩形が当たっていないとき
直線と矩形が衝突していない場合、外積の結果は全てマイナスか、全てプラスになるはずです。
直線と矩形が当たっているとき
直線と矩形が衝突している場合、外積の結果はいくつかがプラスで、いくつかがマイナスになるはずです。
直線と角4点の外積を調べながら、外積の符号が異なる結果が得られた時点で、直線と矩形は当たっているとなります。
直線が矩形の角にぴったりと接しているとき
直線が矩形の角に接している時は外積の値は0になりますので、これも一応当たっているという判定としておきましょう。
外積の値が0になる角が見つかった時点で、直線と矩形は当たっているとなります。
以上で、直線と矩形の衝突についての説明は終わりです。
サンプルコード
/**
* 直線と矩形が当たっているかどうか
* @param line 直線1
* @param rect 矩形
*/
export function isHit(line:Line, rect:Rect)
{
// 矩形の角4点を配列化
const points = [
rect.p1,
rect.p2,
rect.p3,
rect.p4,
];
// 外積の符号を覚えておくための変数
let sign = 0;
// 角4点と直線の方向ベクトルの関係性を調べる
for(let i = 0; i < points.length; ++i) {
// 直線の向きベクトルを v1 とする
const v1 = line.v;
// 直線の任意の点から矩形の角に向かうベクトルをv2 とする
const v2 = Vector2.sub(points[i], line.p);
// 外積を取る
const cross = Vector2.cross(v1, v2);
// 外積の結果が0だったら衝突している
if (cross === 0) return true;
// 初回だけ外積の符号を記憶しておく
if (i == 0) {
sign = Math.sign(cross);
}
// 角2点目以降、外積の符号が変わっていたら交差している
else {
if (sign !== Math.sign(cross)) return true;
}
}
// 外積の結果が全て同じ符号だったら衝突していない。
return false;
}