NEWS

円形オブジェクトによる衝突判定の仕組みと実装

2026.01.08

    ゲーム開発において、物体と物体が触れ合ったことを検知する「衝突判定(当たり判定)」は、最も基本的かつ重要な技術の一つです。本記事では、数学的な背景からJavaScriptによる具体的な実装方法まで、簡潔に解説します。

    衝突判定とは?

    衝突判定とは、デジタル空間上のオブジェクト同士が重なったかどうかを計算によって判定する処理です。プログラムは画面上の見た目を「理解」しているわけではありません。そのため、オブジェクトの座標や大きさをもとに数学的な計算を行い、重なりがある場合に「衝突した」というフラグを立てる必要があります。

    実際にシミュレーターを使って体験してみましょう。
    赤色の円をクリックして、青色の円や黄色の円にくっつけたり、はなしたりしてみてください。右側のコントロールで「Clear」と「No Hit」と書いてある部分が、それぞれ円がぶつかると変化するはずです。

    衝突判定が使われているゲーム

    多くのゲームジャンルでこの技術が活用されています。

    • シューティングゲーム: 自機と敵の弾、あるいは敵機と自分の弾が当たったかの判定。

    • アクションゲーム: キャラクターが地面に着地しているか、敵に攻撃が当たったかの判定。

    • パズルゲーム: 落ちてきたブロックが他のブロックに積み重なったかの判定。

    • スポーツゲーム: ボールがゴールラインを越えたか、選手がボールに触れたかの判定。

    円形を使った衝突判定の数学的計算方法

    円形の衝突判定は、2つの円の中心点どうしの「距離」と、それぞれの「半径」を比較することで行います。

    このような判定のことを衝突判定と呼んでいます。

    計算の基本原理

    2つの円(円Aと円B)があるとき、以下の条件を満たせば「衝突している」とみなします。

    「2点間の距離 < 円Aの半径 + 円Bの半径」

    三平方の定理の活用

    2つの円が重なっているかどうかを判断するには、それぞれの中心点をつないだ直線の長さ(距離)を知る必要があります。この距離を求めるために「三平方の定理(ピタゴラスの定理)」を利用します。

    1. 直角三角形を想定する: 2つの円の中心を点A、点Bとします。点Aと点Bを斜辺とする直角三角形を頭の中で描きます。

    2. 横と縦の差を出す: 2つの点の「横方向の座標の差(横の長さ)」と「縦方向の座標の差(縦の長さ)」を計算します。ソースコード上では、それぞれ dxdy という変数で表されています。

    3. 定理に当てはめる: 三平方の定理では、「底辺の2乗 + 高さの2乗 = 斜辺の2乗」という法則があります。 これを今回のケースに当てはめると、以下のようになります。 「(横の差 × 横の差) + (縦の差 × 縦の差) = 距離の2乗」

    4. 距離を割り出す: 最後に「距離の2乗」のルート(平方根)をとることで、2点間の正確な距離が算出できます。

    この計算で出た距離が、それぞれの円の半径を足した長さよりも短ければ、2つの円は衝突していると判定されます。

    円形を使った衝突判定の実装方法(JavaScript)

    JavaScriptでの具体的な実装例を解説します。

    基本的な判定関数

    以下のコードは、2つの円形オブジェクトが衝突しているかどうかを true または false で返します。

    JavaScript

    /**
     * 2つの円の衝突を判定する関数
     * @param {Object} c1 - 円1 (x, y, r)
     * @param {Object} c2 - 円2 (x, y, r)
     * @returns {boolean} - 衝突していればtrue
     */
    function checkCollision(c1, c2) {
        // 1. 中心座標の差を計算
        const dx = c1.x - c2.x;
        const dy = c1.y - c2.y;
    
        // 2. 三平方の定理で中心点間の距離を計算
        const distance = Math.sqrt(dx * dx + dy * dy);
    
        // 3. 半径の合計を計算
        const sumOfRadii = c1.r + c2.r;
    
        // 4. 距離が半径の合計より小さければ衝突
        return distance < sumOfRadii;
    }

    パフォーマンスの最適化

    実際のゲーム開発では、処理を高速化するために Math.sqrt()(平方根の計算)を避けることがあります。平方根の計算はコンピュータにとって負荷が高いため、両辺を2乗した状態で比較します。

    JavaScript

    // 最適化された判定式
    const isColliding = (dx * dx + dy * dy) < (sumOfRadii * sumOfRadii);

    この方法であれば、数学的な結果を変えずに処理負荷を軽減できます。

    それ以外の衝突判定の方法や種類

    円形以外にも、用途に合わせてさまざまな判定方法が使い分けられます。

    1. 矩形判定(AABB)

    Axis-Aligned Bounding Box(軸平行境界ボックス)と呼ばれます。回転しない長方形同士の重なりを判定する方法です。

    • 特徴: 計算が非常に単純で高速。

    • 用途: UIボタンのクリック判定、単純なプラットフォームゲームなど。

    2. 点と円の判定

    ある一点が円の中に含まれるかを判定します。

    • 計算: 「点と円の中心の距離 < 円の半径」で判定。

    3. カプセル判定

    円筒形の両端に半球をつけたような形状での判定です。

    • 用途: 人型のキャラクターなど、縦長のオブジェクトに適しています。

    衝突判定に関するよくある質問と回答

    Q1. オブジェクトが高速で移動すると、すり抜けてしまうのはなぜですか?

    A1. ゲームの計算は一定の時間刻み(フレーム)ごとに行われるからです。移動速度が速すぎると、あるフレームでは「衝突前」にあり、次のフレームではすでに「衝突後(通り過ぎた後)」の位置に移動してしまうため、判定が一度も成立しません。これを防ぐには、移動の軌跡を線分として判定する「連続的衝突判定(CCD)」が必要です。

    Q2. 複雑な形状のキャラクターはどうやって判定しますか?

    A2. 複数の円や長方形を組み合わせて判定範囲を作ります。これを「ヒットボックス」と呼びます。正確さを求める場合は、より複雑な多角形判定(SATなど)を用いますが、計算負荷が高くなるため、多くの場合は単純な図形の組み合わせで代用されます。

    Q3. 円形判定のメリットは何ですか?

    A3. 最大のメリットは「回転」に強いことです。長方形判定(AABB)の場合、オブジェクトが回転すると判定範囲を計算し直す必要がありますが、円形はどの方向から見ても半径が変わらないため、回転するオブジェクトに対して常に一定の精度を保てます。

    まとめ

    円形を使った衝突判定は、三平方の定理を利用した「中心点間の距離」と「半径の合計」の比較によって実現されます。

    • 特徴: 計算が比較的簡単で、オブジェクトが回転しても精度が維持される。

    • 注意点: 平方根の計算負荷を抑えるため、2乗同士で比較する最適化が一般的。

    この基礎を理解することで、シューティングゲームの被弾処理や、アクションゲームの接触判定など、多様なゲームシステムの基盤を作ることが可能になります。まずはシンプルな2つの円の距離計算から実装を試してみてください。