円筒と球の衝突判定 はじめました
円筒と球の衝突判定って簡単なのでは?
円筒って便利ですよね?
キャラクター同士の衝突判定を考えたとき、「キャラクターの当たり判定を球にして移動の軌跡を円筒にする」っていうのが一番最初にぱっと思いつきますよね?そうでもないですか?
だけどネットにそこまで落ちてない
ネットで衝突判定のアルゴリズム探すんだけど、検索方法が悪いのかいまいち見かけない気がする。
簡単だから
仕方ないので図を書いて考えると、あっさり答えが出てしまった。
なるほど、線分と球の衝突判定をほんの少し拡張しただけなので、あえてネットにまで書く必要がないんですね。(というか、円筒って太さ持った線分だから、そんなの当然の如く分かるでしょ的スタンスなのかもしれない。)
実装は?
適当な図(左が線分と球、右が線分から円筒にする考え方)
線分と球の衝突判定
bool KSphere::operator*(const KSegment& aSegment) const { KVector vec1(mPosition - aSegment.mVec1); KVector vec2(mPosition - aSegment.mVec2); KVector seg(aSegment.mVec2 - aSegment.mVec1); KVector para(vec1.extractParallel(seg)); if (seg.length() == 0.0f) { // 線分の長さがないときは点として判定 return vec1.length() < mRadius; } // 中心座標から線分に垂らした垂線との交点による内分比 float t(para.length() / seg.length()); float dist; // 中心座標と線分の最短距離 if (0 < t && t < 1) dist = (para - vec1).length(); else { // 交点が線分上にない(線分の端との距離を計測) if (t < 0) dist = vec1.length(); if (1 < t) dist = vec2.length(); } return dist < mRadius; }
円筒と球の衝突判定*1
bool KSphere::operator*(const KCylinder& aCylinder) const { KSegment seg(aCylinder.mVec1, aCylinder.mVec2); if (!aCylinder.mRounding) { KVector dir(seg.direction()); float len(seg.length() / 2); KVector center(seg.mVec1 + dir * len); float lenDiff(Math::max(0.0f, len - aCylinder.mRadius)); seg = KSegment(center + dir * lenDiff, center - dir * lenDiff); } return KSphere(mPosition, mRadius + aCylinder.mRadius) * seg; }
円筒と球の衝突判定ってどちゃくそ重い
見たらわかるけど、分岐処理があほみたいに多い。
たとえば「キャラクターの当たり判定を球にして移動の軌跡を円筒にする」みたいなことは、処理が重すぎて毎フレームできたものじゃない。
本末転倒だけど、ネットにないのは実用性がないからなのかもしれない。
妥協案として、キャラクターは自分の半径以上1回の処理で動けないってルールを追加するのが妥当な*2気がする。*3
キャラクターを速く動かしたいなら、球と球の衝突判定にしてフレームレート上げましょう!!
いつ使うんですか?
めったに使えたものではないので、銃弾とかの稀に発生するオブジェクトなら使えるかもしれない。
ただ、それでも線分として処理をした方が速い。
極太レーザーならありなのかもしれない。