Unity なんでもインスペクタに表示していくやつ

このエントリーは、KLab Advent Calendar 2015 の16日目の記事です。

Unityを使ったゲーム開発業務に取り組んでいる、こうさかです。
デバッグ時に便利な、Unityのエディタ拡張を作ったので紹介します。

前提

Unity4.6.9&C#の環境で実装・確認してます。

開発中デバッグめんどくさい問題

もりもりコード書いて、いざ実行すると意図した挙動をしてくれないとき、バグっていそうな箇所にログを仕込む・デバッガを使い内部の状態を見る・気合でコード読むなどの調査をすると思います。しかし、いちいちログ出力コードを書いたり、デバッガを起動したりするのは面倒です。臭い場所が絞れている場合はコードを読めばわかりますが、そもそもあたりがつけられない場合に大量のコードを読むのも時間がかかります。特にゲームなど状態が多く複雑なアプリケーションを開発している場合、バグの調査に多くの時間をとられてしまいがちです。
そこで、常に状態を見ることができれば多少デバッグが楽になるのでは?という発想から、ゲームオブジェクトのフィールド・プロパティをインスペクタに表示するエディタ拡張を作りました。
ちなみにゲームオブジェクトのフィールドだけだったらデフォルトのインスペクタでも表示できます。

サンプル

サンプルプロジェクト

サンプルコンポーネント

using UnityEngine;

[Inspectable]
public class SampleComponent : MonoBehaviour
{
    [Inspectable]
    int sampleInt;

    [Inspectable]
    float sampleFloat;

    [Inspectable]
    public bool SampleBoolean { get; private set; }

    [Inspectable]
    Vector3 SampleVector3 { get { return transform.position; } }

    [Inspectable]
    Color SampleColor { get { return Color.black; } }

    [Inspectable]
    SampleType SampleType { get; set; }

    int ignoreInspection = 1;

    void Start()
    {
        sampleInt = 42;
        sampleFloat = 0f;
        SampleBoolean = true;
        SampleType = new SampleType();
    }

    void Update()
    {
        sampleFloat += Time.deltaTime;
    }
}

こんなコンポーネントを作ってヒエラルキーに設置しておくと

sc1

このように表示されます。

仕組み

カスタムエディタの仕組みを利用して、特定のコンポーネント(DebuggingInspector)をアタッチしたゲームオブジェクトにフォーカスがあたった場合、デフォルトのインスペクタを上書きしデバッグ情報を表示するようになってます。
デバッグ表示対象のコンポーネントはヒエラルキーのルート直下を走査して[Inspectable]属性の有無を確認し抽出しています。[Inspectable]属性がついていた場合は、クラス内に[Inspectable]属性のついたフィールド・プロパティを探してリフレクションを用いて値を取得しインスペクタに表示しています。
デバッグ用ゲームオブジェクトにフォーカスがあたっている場合、基本的には毎フレーム属性の走査が走ってしまいますが、インスペクタ上部にあるAutoRefreshのチェックを外すと更新を行わなくなります。
実装

上記サンプルの

[Inspectable]
SampleType SampleType { get; set; }

では自分で定義した型のプロパティに属性をつけていますが、この場合でもクラスの属性に[Inspectable]をつけることで型定義を辿って入れ子に表示してくれます。

入れ子対象の例

using UnityEngine;

public enum SampleEnum
{
    Yuno,
    Miyako,
    Sae,
    Hiro
}

[Inspectable]    
public class SampleType
{
    [Inspectable]
    Vector2 SampleVector2 { get; set; }

    [Inspectable]
    public SampleEnum SampleEnum { get; private set; }

    public SampleType()
    {
        SampleVector2 = Vector2.one;
        SampleEnum = SampleEnum.Yuno;
    }
}

実際使ってみて

  • 実行中に気軽に中が見れて便利
  • ログ出力コードを書いたり消したりしないでいいのが楽
  • 毎フレームログ出力してしまうよりは遥かに見やすい
  • 雑に[Inspectable]書いておいて放置できるので重要な部分にはとりあえず付けておくと、後々デバッグ時に助けられることが結構あった
  • 副作用のあるプロパティを対象にすると、アクセスのタイミングが変わってしまっておかしくなりそうなので注意が必要
  • 対象が多くなりすぎて見えにくくなってきたのでフォールディングしたい

まとめ

実装簡単で、使ってみるとわりと便利でした。

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。

関連記事

このブログについて

KLabのゲーム開発・運用で培われた技術や挑戦とそのノウハウを発信します。