【Cocos Creator 3.8】HitboxVisualizerの実装:アタッチするだけでCollisionShapeのデバッグ表示を切り替える汎用スクリプト
このガイドでは、PhysicsCollider / Collider2D が持つ衝突形状(CollisionShape)を、ゲーム実行中にいつでも ON/OFF できる汎用コンポーネント「HitboxVisualizer」を実装します。
ノードにこのコンポーネントをアタッチするだけで、デバッグ用の当たり判定可視化(Visible Collision)をボタン感覚で切り替えできるようになり、物理挙動や当たり判定の調整が格段にやりやすくなります。
コンポーネントの設計方針
実現したい機能
- 対象ノードに付いている 3D物理(
PhysicsCollider)または 2D物理(Collider2D)のデバッグ表示をON/OFF する。 - 外部のGameManagerやシングルトンに一切依存せず、このコンポーネント単体で完結する。
- インスペクタから:
- 起動時に可視化するかどうか
- 2D/3Dのどちらを対象にするか
- キー入力でトグルするかどうか
- トグル用のキーコード
を設定できるようにする。
- 必須コンポーネント(Collider / Collider2D)が無い場合は、エラーログを出して安全に無効化する。
デバッグ可視化の考え方
Cocos Creator 3.8 では、物理デバッグ描画は 物理システム単位(2D/3Dそれぞれ)で有効化する仕組みです。
本コンポーネントは、この仕組みを利用しつつ、以下のように動作します。
- 2D物理:
PhysicsSystem2D.instance.debugDrawFlagsを操作してデバッグ描画をON/OFF。- 対象ノードに
Collider2Dが無い場合はエラーを出す。
- 3D物理:
PhysicsSystem.instance.debugDrawFlagsを操作してデバッグ描画をON/OFF。- 対象ノードに
PhysicsCollider(例:BoxColliderなど)が無い場合はエラーを出す。
デバッグ描画は「システム全体」に対して有効化されますが、このコンポーネントが1つでもONにすれば表示され、すべてOFFにすれば非表示という使い方を想定します。
(1シーンに1つ配置する運用をおすすめします。複数配置しても動きますが、最後に操作したものの状態がシステムに反映されます。)
インスペクタで設定可能なプロパティ
HitboxVisualizer に用意する @property は次の通りです。
- use2DPhysics (boolean)
- 説明: 2D物理(Collider2D)を対象にするかどうか。
- true:
Collider2Dを探し、PhysicsSystem2Dのデバッグ描画を操作。 - false: 3D物理(
PhysicsCollider)を対象にする。
- enableOnStart (boolean)
- 説明: ゲーム開始時(
start())に デバッグ表示を有効化するか。 - true: シーン開始と同時に当たり判定が可視化される。
- false: 初期状態は非表示。必要に応じて後述のキー入力やAPIでONにする。
- 説明: ゲーム開始時(
- allowKeyToggle (boolean)
- 説明: キー入力でON/OFFを切り替えられるようにするか。
- true: 指定キーを押すたびに可視化状態をトグル。
- false: キー操作では切り替えない(スクリプトから
setVisibleなどで制御)。
- toggleKeyCode (KeyCode)
- 説明: デバッグ表示をトグルするためのキー。
- デフォルト:
KeyCode.KEY_H(Hitboxの H)。 - 例:
KeyCode.KEY_Dなど、お好みのキーに変更可能。
- logDetail (boolean)
- 説明: トグル時に 現在の状態や対象のCollider情報をログ出力するか。
- true: ON/OFF時に
console.logで詳細を出力。 - false: エラー以外のログを抑制。
この設計により、外部スクリプトに依存せず、インスペクタだけで完結した設定・制御が可能になります。
TypeScriptコードの実装
以下が完成した HitboxVisualizer コンポーネントの全コードです。
import {
_decorator,
Component,
Node,
warn,
error,
input,
Input,
EventKeyboard,
KeyCode,
} from 'cc';
import { PhysicsSystem, EPhysicsDrawFlags, PhysicsCollider } from 'cc';
import { PhysicsSystem2D, EPhysics2DDrawFlags, Collider2D } from 'cc';
const { ccclass, property } = _decorator;
/**
* HitboxVisualizer
*
* 対象ノードに付いている Collider / Collider2D のデバッグ表示を
* 実行中に ON/OFF できる汎用コンポーネント。
*
* 外部の GameManager などには一切依存せず、このスクリプト単体で完結する。
*/
@ccclass('HitboxVisualizer')
export class HitboxVisualizer extends Component {
@property({
tooltip: '2D物理(Collider2D)を対象にするかどうか。\n' +
'ON: PhysicsSystem2D のデバッグ描画を操作します。\n' +
'OFF: 3D物理(PhysicsCollider)を対象にします。'
})
public use2DPhysics: boolean = true;
@property({
tooltip: 'ゲーム開始時(start)に当たり判定のデバッグ表示を有効化するかどうか。'
})
public enableOnStart: boolean = true;
@property({
tooltip: 'キー入力でデバッグ表示をトグルできるようにするかどうか。'
})
public allowKeyToggle: boolean = true;
@property({
tooltip: 'デバッグ表示の ON/OFF を切り替えるキー。\n' +
'allowKeyToggle が ON のときのみ有効です。'
})
public toggleKeyCode: KeyCode = KeyCode.KEY_H;
@property({
tooltip: 'ON/OFF 切り替え時に詳細ログを出力するかどうか。'
})
public logDetail: boolean = true;
/** 対象ノードに存在する Collider2D(use2DPhysics が true のとき) */
private _collider2D: Collider2D | null = null;
/** 対象ノードに存在する PhysicsCollider(use2DPhysics が false のとき) */
private _collider3D: PhysicsCollider | null = null;
/** 現在の可視化状態(システムに設定したフラグの状態) */
private _isVisible: boolean = false;
onLoad () {
// 対象となる Collider コンポーネントを取得しておく
if (this.use2DPhysics) {
this._collider2D = this.getComponent(Collider2D);
if (!this._collider2D) {
error('[HitboxVisualizer] use2DPhysics=true ですが、このノードには Collider2D がアタッチされていません。ノード名:', this.node.name);
}
} else {
this._collider3D = this.getComponent(PhysicsCollider);
if (!this._collider3D) {
error('[HitboxVisualizer] use2DPhysics=false ですが、このノードには PhysicsCollider(BoxCollider など)がアタッチされていません。ノード名:', this.node.name);
}
}
// 入力イベント登録
if (this.allowKeyToggle) {
input.on(Input.EventType.KEY_DOWN, this._onKeyDown, this);
}
}
start () {
// 起動時の可視化状態を設定
if (this.enableOnStart) {
this.setVisible(true);
} else {
this.setVisible(false);
}
}
onDestroy () {
// 入力イベント解除
if (this.allowKeyToggle) {
input.off(Input.EventType.KEY_DOWN, this._onKeyDown, this);
}
}
/**
* デバッグ表示を有効化 / 無効化する公開メソッド。
* 外部スクリプトから直接呼び出してもよい(ただし外部依存は必須ではない)。
*/
public setVisible (visible: boolean) {
this._isVisible = visible;
if (this.use2DPhysics) {
this._apply2DDebugFlags(visible);
} else {
this._apply3DDebugFlags(visible);
}
if (this.logDetail) {
const target = this.use2DPhysics ? '2D Physics' : '3D Physics';
// eslint-disable-next-line no-console
console.log(`[HitboxVisualizer] ${target} hitbox debug draw is now ${visible ? 'ENABLED' : 'DISABLED'}. Node: ${this.node.name}`);
}
}
/**
* 現在の可視化状態を取得。
*/
public isVisible (): boolean {
return this._isVisible;
}
/**
* 現在の可視化状態を反転させる(トグル)。
*/
public toggleVisible () {
this.setVisible(!this._isVisible);
}
// ------------------------
// 内部処理
// ------------------------
private _onKeyDown (event: EventKeyboard) {
if (!this.allowKeyToggle) {
return;
}
if (event.keyCode === this.toggleKeyCode) {
// Collider が存在しない場合は警告を出して何もしない
if (this.use2DPhysics) {
if (!this._collider2D) {
warn('[HitboxVisualizer] Collider2D が見つからないため、トグルできません。ノード名:', this.node.name);
return;
}
} else {
if (!this._collider3D) {
warn('[HitboxVisualizer] PhysicsCollider が見つからないため、トグルできません。ノード名:', this.node.name);
return;
}
}
this.toggleVisible();
}
}
/**
* 2D物理のデバッグ描画フラグを設定。
*/
private _apply2DDebugFlags (visible: boolean) {
const physics2D = PhysicsSystem2D.instance;
if (!physics2D) {
error('[HitboxVisualizer] PhysicsSystem2D.instance が利用できません。2D物理が有効になっているか確認してください。');
return;
}
if (visible) {
// 代表的なフラグをすべてONにする(必要に応じて調整)
physics2D.debugDrawFlags =
EPhysics2DDrawFlags.Aabb |
EPhysics2DDrawFlags.Pair |
EPhysics2DDrawFlags.CenterOfMass |
EPhysics2DDrawFlags.Joint |
EPhysics2DDrawFlags.Shape;
} else {
physics2D.debugDrawFlags = EPhysics2DDrawFlags.None;
}
}
/**
* 3D物理のデバッグ描画フラグを設定。
*/
private _apply3DDebugFlags (visible: boolean) {
const physics3D = PhysicsSystem.instance;
if (!physics3D) {
error('[HitboxVisualizer] PhysicsSystem.instance が利用できません。3D物理が有効になっているか確認してください。');
return;
}
if (visible) {
// 代表的なフラグをすべてONにする(必要に応じて調整)
physics3D.debugDrawFlags =
EPhysicsDrawFlags.AABB |
EPhysicsDrawFlags.PAIR |
EPhysicsDrawFlags.CONTACT |
EPhysicsDrawFlags.JOINT |
EPhysicsDrawFlags.SHAPE;
} else {
physics3D.debugDrawFlags = EPhysicsDrawFlags.NONE;
}
}
}
コードのポイント解説
onLoaduse2DPhysicsの値に応じて、Collider2DまたはPhysicsColliderをgetComponentで取得。- 見つからない場合は
error()でエラーログを出し、防御的に実装。 allowKeyToggleが true の場合、input.on(KEY_DOWN)でキーボードイベントを登録。
startenableOnStartに応じてsetVisible(true/false)を呼び、起動時の可視化状態を決定。
onDestroy- 登録したキーボードイベントを
input.offで解除し、リークを防止。
- 登録したキーボードイベントを
setVisible / toggleVisible / isVisible- デバッグ表示のON/OFFを行う公開API。
- 内部で
_apply2DDebugFlagsまたは_apply3DDebugFlagsを呼び出し、物理システムのフラグを切り替える。 logDetailが true のとき、現在の状態をconsole.logで表示。
_onKeyDownallowKeyToggleが true のときのみ動作。toggleKeyCodeと一致するキーが押されたらtoggleVisible()を呼び出す。- Collider が存在しない場合は
warn()で警告を出し、何もしない。
_apply2DDebugFlags / _apply3DDebugFlags- それぞれ
PhysicsSystem2D.instanceとPhysicsSystem.instanceにアクセスし、debugDrawFlagsを設定。 - 可視化ONのときは、AABB / Shape / Joint など代表的なフラグをまとめてON にしている。
- OFFのときは
None/NONEをセットして完全に非表示。 - 物理システムが利用できない場合は
error()でエラーを通知。
- それぞれ
使用手順と動作確認
ここからは、実際に Cocos Creator 3.8.7 のエディタ上で HitboxVisualizer を使う手順を説明します。
1. スクリプトファイルの作成
- Assets パネルでフォルダを選択(例:
assets/scripts)。 - 右クリック → Create → TypeScript を選択。
- ファイル名を
HitboxVisualizer.tsにする。 - 自動生成された中身をすべて削除し、前章で示した TypeScriptコード全体 を貼り付けて保存。
2. 2D物理用のテスト(Collider2D)
2Dゲームや UI の当たり判定を確認したい場合の例です。
- 2D物理を有効化
- メインメニュー → Project → Project Settings を開く。
- Module や Physics の設定で、Physics2D が有効になっていることを確認。
- テスト用ノードを作成
- Hierarchy パネルで右クリック → Create → 2D Object → Sprite などを選択。
- ノード名を例として
TestBox2Dに変更。
- Collider2D を追加
TestBox2Dノードを選択。- Inspector の Add Component ボタンをクリック。
- Physics 2D → BoxCollider2D(または他の Collider2D)を追加。
- HitboxVisualizer をアタッチ
- 同じく
TestBox2Dノードを選択した状態で、Add Component → Custom → HitboxVisualizer を選択。
- 同じく
- Inspector でプロパティを設定
use2DPhysics: ON(true)enableOnStart: まずは ON(true) にして、起動直後に可視化されることを確認。allowKeyToggle: ON(true)toggleKeyCode: デフォルトのKEY_HのままでOK。logDetail: デバッグ中は ON(true) にしておくと状態が分かりやすい。
- プレビューで確認
- 上部ツールバーの Play ボタン(または Preview)を押してゲームを実行。
- シーンビューまたはゲームビュー上で、
TestBox2Dの周りに 当たり判定の枠線や形状 が表示されていることを確認。 - キーボードの H キー を押すと、デバッグ表示が ON/OFF で切り替わる。
- コンソールに
[HitboxVisualizer] 2D Physics hitbox debug draw is now ENABLED. Node: TestBox2D [HitboxVisualizer] 2D Physics hitbox debug draw is now DISABLED. Node: TestBox2Dのようなログが出ていれば正常動作。
3. 3D物理用のテスト(PhysicsCollider)
3Dゲームなどで 3D Collider の形状を確認したい場合の例です。
- 3D物理を有効化
- メインメニュー → Project → Project Settings。
- Physics や Module 設定で Physics(3D)が有効になっていることを確認。
- テスト用ノードを作成
- Hierarchy パネルで右クリック → Create → 3D Object → Cube などを選択。
- ノード名を例として
TestBox3Dに変更。
- PhysicsCollider(例: BoxCollider)を追加
TestBox3Dノードを選択。- Inspector → Add Component → Physics → BoxCollider を追加。
- HitboxVisualizer をアタッチ
TestBox3Dノードを選択した状態で、Add Component → Custom → HitboxVisualizer を追加。
- Inspector でプロパティを設定
use2DPhysics: OFF(false)(3D物理を対象にするため)。enableOnStart: ON(true)。allowKeyToggle: ON(true)。toggleKeyCode: 任意(デフォルトKEY_HでOK)。logDetail: ON(true)。
- プレビューで確認
- ゲームを実行。
- シーン内の
TestBox3D周辺に、3D Collider のワイヤーフレームが表示される。 - H キー で表示がON/OFFされることを確認。
- コンソールには
[HitboxVisualizer] 3D Physics hitbox debug draw is now ENABLED. Node: TestBox3D [HitboxVisualizer] 3D Physics hitbox debug draw is now DISABLED. Node: TestBox3Dのようなログが出力される。
4. よくあるつまずきポイント
- Collider が無いのに use2DPhysics/use2DPhysics の設定だけ変えた場合
- コンソールに
[HitboxVisualizer] use2DPhysics=true ですが、このノードには Collider2D がアタッチされていません。などのエラーが出ます。
- 対象ノードに 正しい種類の Collider コンポーネント が付いているか確認してください。
- コンソールに
- 物理システム自体が無効な場合
- 2D/3D 物理モジュールがプロジェクト設定で無効だと、
PhysicsSystem2D.instanceやPhysicsSystem.instanceが正しく動作しないことがあります。 - その場合はエラーが出るので、Project Settings → Physics / Module で有効化してください。
- 2D/3D 物理モジュールがプロジェクト設定で無効だと、
- 複数の HitboxVisualizer をシーンに置いた場合
- 物理デバッグ描画は システム単位 なので、最後に
setVisibleしたコンポーネントの状態が全体に適用されます。 - 運用としては、シーンに1つだけ配置するか、どれを「マスター」にするか決めておくと混乱しません。
- 物理デバッグ描画は システム単位 なので、最後に
まとめ
この HitboxVisualizer コンポーネントを導入すると、
- ノードにアタッチするだけで 2D/3D の当たり判定を即座に可視化できる。
- キー入力(デフォルト H)で いつでも ON/OFF 切り替え ができる。
- 外部の GameManager やシングルトンに依存せず、このスクリプト単体で完結している。
- Collider が無い・物理システムが無効などの状況でも、エラーログで原因が分かる防御的実装になっている。
当たり判定のチューニングや物理挙動のデバッグは、目視で形状を確認できるかどうかで効率が大きく変わります。
HitboxVisualizer をプロジェクトの標準ツールとして組み込んでおけば、どのシーンでも同じ操作感でヒットボックスを確認でき、デバッグ時間の短縮に大きく貢献します。
必要に応じて、
- 2D/3D それぞれで有効にしたい
debugDrawFlagsの種類を調整する - キー入力だけでなく、UI ボタンから
setVisible()を呼び出す
といった拡張も簡単に行えます。
まずはこの記事のコードをそのまま導入し、自分のプロジェクトで当たり判定の可視化を試してみてください。




