1. 無職の学び舎
  2. >
  3. 無職はゲーム数学の勉強をする
  4. >
  5. 点と半直線の衝突

点と半直線の衝突

点と直線の衝突ではベクトルの外積を使って判定しましたが、点と半直線ではベクトルの内積を使って判定をします。

しかしながら小数点の細かい数値の問題で、動きを滑らかにするとほとんど衝突しません。

前提知識

ベクトルの内積を使いますので、先に内積について理解しておくことをお勧めします。

考え方

$ \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)
}