部活の時間中にプログラムを組んでいたらどうにかうまいことできたので書いておこうかと思います。
線分 円 当たり判定 とかで調べれば結構該当する情報はヒットするんですが、
ベクトルをまだ習ってないのであんまり理解できなかったんですよね。
まぁ習っていないから分からない、はただの甘えですけどね……これからちゃんと調べて自主的に勉強しよう……
まず考えたのは直線と点の距離です。
[album]523[/album]
距離はこの図の通りで
θ=atan2( py-y1, px-x1 ) - atan2( y2-y1, x2-x1 )
r=sqrt( (px-x1)*(px-x1) + (py-y1)*(py-y1) )
[追記]画像では距離に絶対値記号を付け忘れました。正しくは|r*sinθ|でした。
です。
これはおk
次は場合分けです。
線分と円が接触している場合、次の2通りが考えられます。
すなわち
1.線分の始点(終点)と円が接触している。
2.線分と円が2点で交わっている。
[album]524[/album]
です。
1.は単純に円と点の当たり判定なので省略。
2.であるかどうかの判定をどうすればいいのか少し考えた結果、
以下の図の印をつけた角が双方とも鋭角もしくは直角であり、かつ中心点と線分の距離が円の半径r以下である
場合2.が成立すると気付いたので、これを採用。
[album]525[/album]
角をそれぞれθ1, θ2とした時に双方とも鋭角ならば
cosθ1 >= 0, cosθ2 >= 0の両方が真である。
よって
接触判定のコードは
/*
* @brief 線分と円の接触判定
* @param x1, y1, x2, y2 線分の始点と終点の座標
* cx, cy 円の中心点の座標
* r 円の半径
* @return 判定結果
*/
bool CheckHitLineToCircle( float x1, float y1, float x2, float y2, float cx, float cy, float r ){
float r1 = sqrt( (cx-x1)*(cx-x1) + (cy-y1)*(cy-y1) ); // (x1,y1)と(cx,cy)の距離
float r2 = sqrt( (cx-x2)*(cx-x2) + (cy-y2)*(cy-y2) ); // (x2,y2)と(cx,cy)の距離
float t1 = atan2( cy-y1, cx-x1 ) - atan2( y2-y1, x2-x1 ); // (x2,y2)-(x1,y1)-(cx,cy)の成す角
float t2 = atan2( cy-y2, cx-x2 ) - atan2( y1-y2, x1-x2 ); // (x1,y1)-(x2,y2)-(cx,cy)の成す角
float x = fabs( sin(t1) * r1 ); // (x1,y1),(x2,y2)を通る直線と円の中心点の距離
return ( r1 0 && cos(t2) > 0 && x < r );
}
……前回までの日記で作っていたゲームは一旦設計を見直しつつモリモリと作りなおしてます。