This explanation is currently available in Japanese.
ひとことで
物体が 1 フレームの間に動く通り道全体を調べて、途中で何かに触れる瞬間を求める衝突判定です。ふつうの(離散的な)判定は、各フレームの位置だけを見るので、速い物体が薄い壁を 1 フレームで飛び越えると、壁の手前と向こう側にしかいない瞬間になり、衝突を見逃します(トンネリング、すり抜け)。連続衝突判定(CCD)は、前の位置から次の位置までを太さのある線分として掃引し、最初に接触する時刻(TOI)を求めるので、どんなに速くても当たります。
ゲームでの使いどころ
- 弾・矢・投げた物:速い弾が敵や壁をすり抜けないようにする。
- プレイヤーの高速移動:ダッシュや落下の速度が大きくなっても、床や壁を抜けない。
- 物理エンジンの設定:Unity の Collision Detection(Continuous)、PhysX や Box2D の「bullet」フラグなど、速い物体だけに CCD を有効にする。
- 形状キャスト:「この位置からこの向きへ球を動かしたら、どこで何に当たるか」を調べる(スフィアキャスト、ボックスキャスト)。キャラクターの移動や、壁ぎわの押し戻しに使う。
しくみ
すり抜けが起きる条件:1 フレームに進む距離 が、壁の厚さと物体の大きさの合計より大きいと、重なる瞬間がないまま通り過ぎることがあります。
( は壁の厚さ、 は物体の半径)。速さ 120 m/s の弾を 60 Hz で更新すると、1 フレームに 2 m 進むので、厚さ 10 cm の壁は簡単にすり抜けます。
対策 1:サブステップ:1 フレームを細かく刻み、刻みごとに判定します。確実ですが、刻むほど判定の回数が増えます。
対策 2:掃引(形状キャスト):物体を、前の位置 から次の位置 へ動く線分として扱い、相手を物体の半径だけ太らせた形(ミンコフスキー和)と線分の交差を調べます。球と平面・球と箱などは、レイキャストと同じ式で最初に触れる割合 が求まります。
対策 3:保守的な前進:一般の凸形状どうしでは、GJK で今の距離 を求め、「近づく速さの上限」 で割った時間 だけは確実にぶつからないので、その分だけ進めることをくり返して接触時刻に近づきます。
実装のポイント
- 速い物体だけに使う:CCD は通常の判定より重いので、速さが一定以上の物体や、弾・プレイヤーなど大事な物体だけに使います。
- 残りの時間:接触した時刻 で止めたあと、反射させた向きに残りの時間 だけ進めると、エネルギーを失わずに跳ね返ります。
- 回転:回転しながら動く細長い物体は、位置だけの掃引では端がすり抜けます。回転も考える CCD(保守的な前進)が必要です。
- 固定の時間刻みと組み合わせる:描画のフレームレートが落ちて が大きくなると、すり抜けが起きやすくなります。物理は固定の刻みで更新します。
つまずきやすい点
- 薄い壁を作らない:CCD がなくても、壁に十分な厚みを持たせるだけで、多くのすり抜けは防げます。レベル作りの段階で気をつけます。
- 動く物体どうし:両方が速く動く場合、片方だけを掃引しても見逃します。相対的な動きで調べます。
- 接触の時刻で止めすぎる:毎回ぴったり接触時刻で止めると、斜めに壁へ当たったときに滑らずに止まってしまいます。残りの時間で壁に沿って滑らせます。
デモで試すこと
- 3 本の通路に、同じ速さの弾を同じ時間刻みで撃ち、スローモーションで見せています。青い点は、物理の更新ごとの弾の位置です。
- 「離散」では、点が壁の手前と向こう側にしかなく、弾がすり抜けて緑になることがあります。「すり抜け」の回数を比べてください。
- 「サブステップ」は細かく刻んで必ず当てますが、判定の回数がずっと多くなります。「連続」は、通り道(黄色)と壁の交差から、1 回の判定で当たる位置を求めます。
- 「弾の速さ」を下げるか「物理の更新」を増やして、1 ステップに進む距離が壁の厚さより小さくなると、離散でも当たるようになります。