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

直線と直線の衝突

直線が衝突すると線が赤くなります。

考え方

直線があたっているかどうかは、2つの直線が平行かどうかを調べるだけでわかります。

2つの直線が平行でないのならば、必ずどこかで衝突するからです。

また2つの直線が平行な場合でも、直線が完全に重なり合っている場合があります。

このケースも判定できるようにしてみます。

直線が平行かどうか

2つの直線が平行の場合、直線の方向ベクトル$\vec{v1}$ と $\vec{v2}$ も平行になるため、$\vec{v1}$ と $\vec{v2}$ の外積は0になります。

$\vec{v1} /\!/ \vec{v2} ならば、\vec{v1} \times \vec{v2} = 0$

直線が交差しているかどうかであれば、この判定だけで終了です。

直線が重なっているかどうか

直線上の点 $A$ から $B$ に向かうベクトルを $\vec{v}$ とします。

2つの直線が平行でも、重なっていないとき、
$\vec{v}$ は 直線の向きベクトル $\vec{v1}$ と平行になっていないのがわかると思います。

2つの直線が重なっている場合は
この $\vec{v}$ と $\vec{v1}$ は平行になります。

よって、直線が重なっているかどうかは
$\vec{v}$ と ${\vec{v1}}$ の 外積をとって、外積が0だったら重なっていると判定できます。

直線が重なっている時
$\vec{v} \times {\vec{v1}} = 0$

余談、$A$ と $B$ が重なっていたら?

また、$A$ と $B$ の位置が完全に重なっている場合、$\vec{v}$ は ゼロベクトルになってしまいます。

ゼロベクトルは向きがないので、$\vec{v1}$ と平行かどうかはわかりません。

とはいえ、直線が完全に同じ座標を通るということは、間違いなく当たっているという事はわかります。

ゼロベクトルと $\vec{v}$ との外積も結果は 0 になるので、$A$ と $B$ が重なっていたら?と場合分けをする必要もなさそうです。

サンプルコード

直線が交差しているかどうかと、重なっているかどうかは分けて定義したほうがいいかなと思います。

/**
  * 直線と直線が当たっているかどうか
  * @param l1 直線1
  * @param l2 直線2
  */
 function isHit(l1:Line, l2:Line) 
 {
   // 直線が平行でなければ必ず当たっている
   return (Vector2.cross(l1.v, l2.v) !== 0);
 }
 
 /**
  * 直線と直線が平行であたっているかどうか(重なっているか)
  * @param l1 直線1
  * @param l2 直線2
  */
 function isHitParallel(l1:Line, l2:Line)
 {
   // 直線1の方向ベクトルを v1
   const v1 = l1.v;
 
   // 直線1上の点から直線2上の点に向かうベクトルを v2
   const v2 = Vector2.sub(l1.p, l2.p);
 
   // v1 と v2 の外積が0だったら、線が重なっている
   // (小数点誤差対策)
   return (Math.abs(Vector2.cross(v1, v2)) < Define.EPSILON);
 }