【ゲーム制作】DirectXで当たり判定を可視化する方法|Gizmos風デバッグ描画をC++で実装

DirectXで当たり判定を可視化するGizmos風デバッグ描画のイメージ ゲーム制作

今回は、ゲーム制作でよく出てくる「DirectXで当たり判定を可視化する方法(UnityのGizmosのようなデバッグ描画)」について解説していきます。

「当たり判定が合ってるのか目で確認したい」
「UnityのGizmosみたいな線をDirectXでも描きたい」
「見えないから、当たってるのか外れてるのか分からない…」

こんな疑問はありませんか?

Unityなら OnDrawGizmos で当たり判定の枠がエディタに出ますが、自作エンジンやDirectXには当然そんな機能はありません。でも当たり判定のデバッグは、見えるかどうかで作業効率が10倍変わります。自分で「デバッグ描画」を用意しましょう。

この記事を読み終えると、あなたはデバッグ描画の考え方・線でボックスや円を描く方法・実装のコツ・初心者がハマりやすいミスをしっかり理解できると思いますので、ぜひ最後まで読んでいただけると嬉しいです。当たり判定そのものはAABBの当たり判定の記事もどうぞ。

デバッグ描画の考え方

難しく考える必要はありません。Gizmosの正体は、当たり判定の形をそのまま「線」で描いているだけです。

  • AABB(四角い判定)→ 4本の線で四角を描く
  • 円の判定 → 短い線をたくさん繋いで円に見せる
  • 当たっている間だけ色を赤にする

ポイントは、これをゲーム本体とは別の描画として重ねること。ゲームの絵を描いたあと、その上に判定の線を上書きします。デバッグ時だけ表示し、リリースでは消せるようにしておくのが定番です。

DirectXでAABBの当たり判定をワイヤーフレームで可視化したデバッグ描画
自作のDirectXプロジェクトで実際にデバッグ描画を実装した結果。モデルの頂点からAABB(軸平行境界ボックス)を計算し、ワイヤーフレームで重ねて描いています。当たり判定の範囲が目で見えるようになります。

線をためて、まとめて描く仕組み

実装のコツは、「描きたい線をいったんリストにためて、フレームの最後にまとめて描く」ことです。こうすると、どこからでも気軽に「線を描いて」と頼めます。

#include <vector>
#include <DirectXMath.h>
using namespace DirectX;

struct DebugVertex {
    XMFLOAT3 pos;
    XMFLOAT4 color;
};

class DebugDraw {
public:
    // 線を1本ためる
    void AddLine(const XMFLOAT3& a, const XMFLOAT3& b, const XMFLOAT4& color) {
        vertices_.push_back({ a, color });
        vertices_.push_back({ b, color });
    }

    // 四角い枠を描く(AABBの可視化)
    void AddBox(float minX, float minY, float maxX, float maxY,
                const XMFLOAT4& color) {
        XMFLOAT3 p0{ minX, minY, 0 }, p1{ maxX, minY, 0 };
        XMFLOAT3 p2{ maxX, maxY, 0 }, p3{ minX, maxY, 0 };
        AddLine(p0, p1, color); // 下
        AddLine(p1, p2, color); // 右
        AddLine(p2, p3, color); // 上
        AddLine(p3, p0, color); // 左
    }

    void Clear() { vertices_.clear(); }

private:
    std::vector<DebugVertex> vertices_;
};

AddBox は、四隅を4本の線で結んでいるだけです。これで四角い当たり判定の枠が描けます。

円を線で描く

円は「線分をたくさん繋ぐ」と表現できます。角度を少しずつ進めて、前の点と今の点を線で結ぶのを繰り返すだけです。三角関数の出番です(三角関数をゲームで使う記事もどうぞ)。

void AddCircle(float cx, float cy, float radius,
               const XMFLOAT4& color, int segments = 24) {
    const float step = XM_2PI / segments;
    for (int i = 0; i < segments; ++i) {
        float a0 = step * i;
        float a1 = step * (i + 1);
        XMFLOAT3 p0{ cx + cosf(a0) * radius, cy + sinf(a0) * radius, 0 };
        XMFLOAT3 p1{ cx + cosf(a1) * radius, cy + sinf(a1) * radius, 0 };
        AddLine(p0, p1, color); // 隣り合う点を結ぶ
    }
}

segments(分割数)を増やすほど滑らかな円になります。24くらいで十分きれいに見えます。

描画と当たり判定を連動させる

あとは、当たり判定の結果で色を変えるだけです。当たっていたら赤、外れていたら緑。これだけで一気にデバッグしやすくなります。

const XMFLOAT4 GREEN{ 0, 1, 0, 1 };
const XMFLOAT4 RED  { 1, 0, 0, 1 };

bool hit = CheckHit(player, enemy); // 当たり判定
XMFLOAT4 color = hit ? RED : GREEN;

debug.AddBox(player.minX, player.minY, player.maxX, player.maxY, color);

// フレームの最後に debug の中身をまとめて線描画 → Clear()

実際の線の描画は、プリミティブトポロジを LINELIST にして頂点を流し込むだけです。三角形ではなく線として描く指定にするのがポイントです。

【重要】私が実際にデバッグ描画で困った体験談

自作エンジンで当たり判定のデバッグ描画を入れたとき、線が一切表示されず、真っ黒な画面とにらめっこを1時間続けました。

原因はプリミティブトポロジの設定漏れ。三角形リストのままだったので、線の頂点が2個ずつしかないと「三角形にならない」と判断され、何も描かれていなかったんです。IASetPrimitiveTopologyLINELIST にしたら、あっさり出ました。

もう一つ。線は出たもののゲームのキャラの裏に隠れて見えないという問題もありました。これは深度テストのせい。デバッグ線は最前面に出したいので、深度テストをオフにするか、一番最後に描くようにして解決しました。

この2つを乗り越えたら、当たり判定のバグ取りが劇的に楽になりました。「見える」だけで世界が変わると実感した瞬間です。

デバッグ描画のよくある失敗例と対処法

①プリミティブトポロジが三角形のまま

体験談のとおり、線が出ません。線を描く前に LINELIST に切り替えるのを忘れないでください。

②深度テストで隠れる

キャラの裏に回って見えなくなります。デバッグ線は一番最後に、深度テストなしで描くと確実に最前面に出ます。

③Clearし忘れて線が残り続ける

毎フレーム Clear() しないと、線がどんどん溜まって重くなり、残像のように残ります。「ためる→描く→クリア」を1セットにしましょう。

注意点

  • 線描画はLINELIST で。三角形設定のままだと出ない
  • デバッグ線は最後に・深度テストなしで最前面に
  • リリースビルドでは丸ごと無効化できるようにしておく

まとめ

  • Gizmos風のデバッグ描画は当たり判定を線で描くだけ
  • 線をためてフレーム最後にまとめて描くと使いやすい
  • 当たり判定の結果で色を変えると一目で分かる
  • ハマりどころはトポロジ設定と深度テスト

当たり判定は「見える化」した瞬間にデバッグが一気に楽になります。まずは四角い枠を1つ描くところから始めてみてください。

関連記事