点と半直線の衝突
点と直線の衝突ではベクトルの外積を使って判定しましたが、点と半直線ではベクトルの内積を使って判定をします。
しかしながら小数点の細かい数値の問題で、動きを滑らかにするとほとんど衝突しません。
前提知識
ベクトルの内積を使いますので、先に内積について理解しておくことをお勧めします。
考え方
$ \vec{a} $:半直線の向きを表すベクトル
$ \vec{b} $:半直線の始点から●に向かうベクトル
●を動かしながらグラフ内に表示されている $ \vec{a} \cdot \vec{b} $ と $ |\vec{a}| |\vec{b}| $ の数値を確認してみて下さい。
●が 半直線の上にくるとき、$ \vec{a} \cdot \vec{b} $ と $ |\vec{a}| |\vec{b}| $ が同じ数値になると思います。
$ \vec{a} \cdot \vec{b} $ は $\vec{a}$ と $\vec{b}$ の内積で、$ |\vec{a}| |\vec{b}| $ は $\vec{a}$ と $\vec{b}$ の長さを掛け合わせたものです。
●が半直線に当たっている場合、$ \vec{a} \cdot \vec{b} $ と $ |\vec{a}| |\vec{b}| $ は同じ値になるので、$ \vec{a} \cdot \vec{b} = |\vec{a}| |\vec{b}| $ だったら点と半直線は当たっていると判定します。
なぜ、$ \vec{a} \cdot \vec{b} = |\vec{a}| |\vec{b}| $ になるのか
$ \vec{a} \cdot \vec{b} = |\vec{a}| |\vec{b}| cos(\theta) $
これは内積の計算式になりますが、最後に $cos(\theta)$ を掛けているのがわかると思います。
点が半直線上に来るとき、$ \vec{a}$ と $\vec{b} $ は平行になるため、ベクトルの間の角度は0度となり、内積は以下のようになります。
$ \vec{a} \cdot \vec{b} = |\vec{a}| |\vec{b}| cos(0) $
$ \ \ \ \ \ \ \ = |\vec{a}| |\vec{b}| 1 $ : $ cos(0) = 1 $ なので
$ \ \ \ \ \ \ \ = |\vec{a}| |\vec{b}| $
$ \vec{a} \cdot \vec{b} = |\vec{a}| |\vec{b}| $ になりました。
サンプルコード
/**
* 点と半直線が当たっているかどうか
* @param p 点
* @param ray 半直線
*/
function intercect(p:Vector2, ray: Ray)
{
// 半直線の方向を表すベクトルをa
const a = ray.v;
// 半直線の始点からpに向かうベクトルを b
const b = Vector2.sub(p, ray.p);
// a と b の長さを掛け合わせたものを ab
const ab = a.magunitude * b.magnitude;
// a と b の内積を dot
const dot = Vector2.dot(a, b);
// ab と dot が同じだったら当たっている
return (ab === dot)
}