当たり判定 線分と円

Actorの持っている円形の領域と線分との当たり判定

学校で習ったベクトルがようやく役にたつとき!



基本的な考え方は、線分ABと点Cを中心とした円を考える。点C線分ABにおろした垂線が、円の中心との最短距離になる。こいつと円の半径を比較して、半径の方が小さかったら当たってない、大きかったらあたっていることになる。また、垂線との交点Hが線分ABの間にないときは、最短距離が、ACになったりBCになったりする。
こんな感じ




この場合はHCよりもACの方が短い。

問題はHCの長さを求める計算だけど、まず点Hの場所をベクトルを使って求める。
ベクトルAHはベクトルABをt倍したものとできるので、tを求めれば場所がわかる。




 という式の変形でtが求められる。
public static bool CircleLineCollide(Vector2 center, float radius,Vector2 lineStart, Vector2 lineEnd, ref CircleLineCollisionResult result) {

 Vector2 AC = center - lineStart;
 Vector2 AB = lineEnd - lineStart;
 float ab2 = AB.LengthSquared();
 if(ab2 <= 0f) {
  return false;
 }
 float acab = Vector2.Dot(AC, AB);
 float t = acab / ab2;

tが負の場合、または1以上の場合は線分ABからはみ出てるので調整する
if(t < 0.0f) {
  t = 0.0f;//点Hが点Aの場所になる
 } else if(t > 1.0f) {
  t = 1.0f;//点Hが点Bの場所になる
 } 

交点は当たり判定通知用の構造体、CircleLineCollisionResultにしまう。

円の半径と、距離を比較して結果を出す。

result.Point = lineStart + t * AB;
 result.Normal = center - result.Point;

 float h2 = result.Normal.LengthSquared();
 float r2 = radius * radius;
 if(h2 > r2) {
  result.Collision = false;
 } else {
  result.Normal.Normalize();
  result.Distance = (radius - (center - result.Point).Length());
  result.Collision = true;
 }

 return result.Collision;
} 
 
きれいに書いてみたかったのでTEXを使ってみた。環境をつくるのがめんどい。
図はGRAPESを使ってみました。使い方が独特だけど、簡単に図形がかけてよい感じ。

0 コメント :: 当たり判定 線分と円

コメントを投稿