Unity | Inspectorを拡張するサンプルScript集

Inspectorを拡張するサンプルScript集です。適当なゲームオブジェクトに取り付けて確認できます。

テンプレート

何もしない拡張と基本的な説明です。

MonoBehaviour拡張

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class Template : MonoBehaviour
    {

    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(Template))]
    public class TemplateEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            Template myTarget = (Template)target;
            DrawDefaultInspector();
        }
    }
    #endif
}

プラットフォーム依存コンパイル(Platform dependent compilation

#if UNITY_EDITOR
using UnityEditor;
#endif

この「#if ~ #endif」の部分はプラットフォーム依存コンパイルでプラットフォームを判別しコンパイルします。

inspector拡張はUnityエディタ上でのみ使用するため、それ以外の場所ではコンパイルしません。

(拡張用のコードを別のファイルに分けて書き、「Editor」 フォルダー(エディターのみで動作する特殊なフォルダ名)に入れる事でも可能ですが、面倒くさいので今回はまとめています。)

CustomEditor Attribute

カスタムエディター(CustomEditor)は、デフォルトのインスペクターのレイアウトの代わりに任意のレイアウトを表示出来るようにする追加スクリプトです。

クラス名は「拡張する元のクラス名」+「Editor」となっています。また、Editorを継承します。

    [CustomEditor(typeof(Template))]
    public class TemplateEditor : Editor
    {
    }

OnInspectorGUI()

カスタムインスペクターを作成し、インスペクターの表示を上書き(override)します。

簡単にまとめると次のような特徴。

  • 拡張後は元のinspectorが表示されない状態になります。
  • 描画は上から順に処理されます。(→応じて並び順が変わります)
  • 全ての項目を表示する場合には、下のDrawDefaultInspector()を使用します。

Template myTarget = (Template)target;

これは、クラスを取得する(上記コードではTemplateクラス)ために使用しています。

inspectorから対象クラス内のpublic変数の取得や変更、public関数を実行する際にに使用します。

クラス内変数の変更、関数の実行が無い場合は不要です。

DrawDefaultInspector()

通常のインスペクターを全て表示します。全体を変更しない場合やデフォルトのインスペクターにボタン等のレイアウトを追加する場合に使用します。

返り値はBool型で変化があるとTrueを返します。

inspector全体を変更する、全体を表示しない場合は不要です。

EditorGUILayoutとGUILayoutとEditorGUIの違いメモ

GUILayoutは、GUIの配置やボタン等の機能を扱います。(UnityEngine)

EditorGUILayoutは、GUIのパラメータフィールド等の要素とその配置を扱います。(UnityEditor)

→ Property Drawer(Attribute作成等)では使用できない関数です。

EditorGUIは、EditorGUILayoutと機能は同じで、自動レイアウトが行われないものです。(UnityEditor)

→混乱したら諦めてリファレンスを…。

ScriptableObject拡張

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    [CreateAssetMenu(fileName = "new Template SO", menuName = "BlueBreath/TemplateSO")]
    public class TemplateSO : ScriptableObject
    {

    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(TemplateSO))]
    public class TemplateSOEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            TemplateSO myTarget = (TemplateSO)target;
            DrawDefaultInspector();

            if(GUILayout.Button("Save Asset")){
                EditorUtility.SetDirty(myTarget);
                AssetDatabase.SaveAssets();
            }            
        }
    }
    #endif
}

ScriptableObjectのセーブ

if(GUILayout.Button("Save Asset")){
    EditorUtility.SetDirty(myTarget);
    AssetDatabase.SaveAssets();
}    

Editor拡張(追加したボタンなど)によってList等に値を変更した場合には変更通知が行われず、Unityを閉じた際にScriptableObjectのデータが消えてしまう事があります。対処するため、更新の通知と保存を行います。

また、ScriptableObjectに保存可能な値(値が消えてしまう場合)には、スクリプトのシリアル化を確認してください。

レイアウト(EditorGUILayout)サンプルScript

ヘルプボックス(HelpBox)

追加の囲みメッセージと特定のアイコンを追加できます。

public static void HelpBox (string message, MessageType type);

HelpBoxのサンプルScriptを取り付けたinspector
HelpBoxのサンプルScriptを取り付けたinspector

HelpBoxでは、メッセージとヘルプボックスを作成し、4種類の形式からテキスト情報を表示できます。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class HelpBox : MonoBehaviour
    {
        public int i = 0;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(HelpBox))]
    public class HelpBoxEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            //HelpBox myTarget = (HelpBox)target;

            EditorGUILayout.HelpBox("MsgBox",MessageType.None);
            DrawDefaultInspector();
            EditorGUILayout.HelpBox("InfoMsg",MessageType.Info);
            EditorGUILayout.HelpBox("WarningMsg",MessageType.Warning);
            EditorGUILayout.HelpBox("ErrorMsg",MessageType.Error);
        }
    }
    #endif
}

public static void HelpBox (string message, MessageType type, bool wide);

HelpBoxのサンプルScript(wide =  false)を取り付けたinspector
HelpBoxのサンプルScript(wide = false)を取り付けたinspector

wideの値がtrueもしくは引数無しの場合は幅全体をカバーします。falseの場合は上図のようにコントロール部分のみをカバーします。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class HelpBox : MonoBehaviour
    {
        public int i = 0;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(HelpBox))]
    public class HelpBoxEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            //HelpBox myTarget = (HelpBox)target;

            EditorGUILayout.HelpBox("MsgBox",MessageType.None,false);
            DrawDefaultInspector();
            EditorGUILayout.HelpBox("InfoMsg",MessageType.Info,false);
            EditorGUILayout.HelpBox("WarningMsg",MessageType.Warning,false);
            EditorGUILayout.HelpBox("ErrorMsg",MessageType.Error,false);
        }
    }
    #endif
}

数値の入力

数値FieldのサンプルScriptを取り付けたinspector
数値FieldのサンプルScriptを取り付けたinspector
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class ParamFields : MonoBehaviour
    {
        public int i, i1, i2, i3;
        public long l;
        public float f, f1, f2, f3;
        public double d;
        public Vector2 vector2 = new Vector2();
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(ParamFields))]
    public class ParamFieldsEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            ParamFields myTarget = (ParamFields)target;
            //DrawDefaultInspector();
            //int関連の入力
            myTarget.i = EditorGUILayout.IntField(myTarget.i);
            myTarget.i1 = EditorGUILayout.IntField("i1", myTarget.i1);
            myTarget.i2 = EditorGUILayout.IntSlider(myTarget.i2, 5, 15);
            myTarget.i3 = EditorGUILayout.IntSlider("i3", myTarget.i3, 0, 5);
            //long関連の入力
            myTarget.l = EditorGUILayout.LongField(myTarget.l);
            //float関連の入力
            myTarget.f = EditorGUILayout.FloatField(myTarget.f);
            myTarget.f1 = EditorGUILayout.FloatField("f1", myTarget.f1);
            myTarget.f2 = EditorGUILayout.Slider(myTarget.f2, 5f, 15f);
            myTarget.f3 = EditorGUILayout.Slider("f3", myTarget.f3, 0f, 5f);
            //double関連の入力
            myTarget.d = EditorGUILayout.DoubleField(myTarget.d);
            //Vector2関連の入力
            myTarget.vector2 = EditorGUILayout.Vector2Field(new GUIContent("接点t", "ぉーん"), myTarget.vector2);
        }
    }
    #endif
}

ラベル(Label)

ラベルを表示する例です。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class LabelField : MonoBehaviour
    {
        public int i;
        public string str;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(LabelField))]
    public class LabelFieldEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            //LabelField myTarget = (LabelField)target;
            EditorGUILayout.LabelField("デフォルトインスペクター");
            DrawDefaultInspector();
        }
    }
    #endif
}

プルダウン(Enum)

EnumPopupのサンプルScriptを取り付けたinspector
EnumPopupのサンプルScriptを取り付けたinspector

プルダウン(ドロップダウンリスト)を表示する例です。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public enum Rarity{
        Common = 0,
        Rare = 1,
        SuperRare = 2
    }
    public class EnumPopup : MonoBehaviour
    {
        public Rarity rarity = Rarity.Common;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(EnumPopup))]
    public class EnumPopupEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            EnumPopup myTarget = (EnumPopup)target;
            //DrawDefaultInspector();

            myTarget.rarity = (Rarity)EditorGUILayout.EnumPopup(myTarget.rarity);
        }
    }
    #endif
}

文字列(テキスト)の入力欄

通常の文字列 (TextField)

TextFieldのサンプルScriptを取り付けたinspector

TextFieldではラベル有り、無しのstring入力欄を作成できます。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class TextField : MonoBehaviour
    {
        public string text;
        public string text2;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(TextField))]
    public class TextFieldEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            TextField myTarget = (TextField)target;
            //DrawDefaultInspector();
            myTarget.text = EditorGUILayout.TextField(myTarget.text);
            myTarget.text2 = EditorGUILayout.TextField("ラベル", myTarget.text2);
        }
    }
    #endif
}

複数行の文字列 (TextArea)

TextAreaのサンプルScriptを取り付けたinspector

3つの例で実装しています。

  • (1~3の例)スクロールビューの要素とその子要素として考えられる内側の要素それぞれのサイズを指定することができます。
  • (2~3の例)スクロールビューによってその子要素を並べた中で、表示する範囲を決めることが出来ます
    (要素を並べた中でRect範囲を切り取って表示するかと同じ)。
  • (2~3の例)サイズについてWidth、Heightだけではなく、要素のサイズ最大値MaxWidth、MaxHeightが指定できます。
  • (3の例)TextArea内の文字列に対してTextArea用のGUIStyleを作成、適用することで、改行無しに折り返しを行う事もできます。

これによって、BeginScrollView~EndScrollViewに含まれる要素全てを上下若しくは左右にはみ出さないようにすることで、常に縦スクロールのみ、常に横スクロールのみが実装できます

using System;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class TextArea : MonoBehaviour
    {
        public string text;
        public string text2;
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(TextArea))]
    public class TextAreaEditor : Editor
    {
        public GUI gUI = new GUI();
        public Vector2 scrollPosition;
        public override void OnInspectorGUI()
        {
            TextArea myTarget = (TextArea)target;
            //DrawDefaultInspector();
            
            //高さ120pxの入力欄
            myTarget.text = EditorGUILayout.TextArea(myTarget.text,GUILayout.Height(120f));
            
            //スクロール可能な入力欄(テキストの自動折り返しなし)
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, 
                //水平スクロールバーははみ出した場合に表示、垂直スクロールバーを常に表示
                //alwayShowHorizontal = false, alwayShowVertical = true
                false,true,
                //レイアウトの幅、高さ
                GUILayout.Width(240f),
                GUILayout.Height(120f)
                );
            myTarget.text2 = EditorGUILayout.TextArea(
                myTarget.text2,                 
                //幅が240を超えないように指定
                GUILayout.MaxWidth(240f)
                );
            EditorGUILayout.EndScrollView();

            //スクロール可能な入力欄(テキストの自動折り返しあり)
            //テキストエリアのスタイルを作成
            GUIStyle textAreaStyle = new GUIStyle(EditorStyles.textArea){
                //折り返しを有効にします
                wordWrap = true
            };
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, 
                //水平スクロールバーははみ出した場合に表示、垂直スクロールバーを常に表示
                //alwayShowHorizontal = false, alwayShowVertical = true
                false,true,
                //レイアウトの幅、高さ
                GUILayout.Width(240f),
                GUILayout.Height(120f)
                );
            myTarget.text2 = EditorGUILayout.TextArea(
                myTarget.text2,
                //作成したtextAreaStyleを適用
                textAreaStyle,              
                //幅が240を超えないように指定
                GUILayout.MaxWidth(240f)
                );
            EditorGUILayout.EndScrollView();
        }
    }
    #endif
}

関数を実行するボタン(Button)

GUILayout.Buttonで実質クリッカーinspector

ButtonはGUILayoutにあります

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class EditorButton : MonoBehaviour
    {
        public int score = 0;
        public void AddScore(int value){
            score += value;
        }
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(EditorButton))]
    public class EditorButtonEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            EditorButton myTarget = (EditorButton)target;
            DrawDefaultInspector();
            if(GUILayout.Button("Button"))myTarget.AddScore(2);
        }
    }
    #endif
}

横に並べる(BeginHorizontal, EndHorizontal)

ボタンを横に並べる
ボタンを横に並べる

EditorGUIを横に並べる場合は、「EditorGUILayout.BeginHorizontal」と「EditorGUILayout.EndHorizontal」を使用します。

using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class Horizontal : MonoBehaviour
    {
        public int param = 10;
        public void AddParam(int value) => param += value ;
        public void SubParam(int value) => param -= value ;
        
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(Horizontal))]
    public class HorizontalEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            Horizontal myTarget = (Horizontal)target;
            //DrawDefaultInspector();
            myTarget.param = EditorGUILayout.IntField("param", myTarget.param);
            EditorGUILayout.BeginHorizontal();
            if(GUILayout.Button("Add"))myTarget.AddParam(1);
            if(GUILayout.Button("Sub"))myTarget.SubParam(1);
            EditorGUILayout.EndHorizontal();
        }
    }
    #endif
}

グラデーション(GradientField)

GradientFieldのサンプルScriptを取り付けたinspector
GradientFieldのサンプルScriptを取り付けたinspector
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace BlueBreath.Sample
{
    public class GradientField : MonoBehaviour
    {
        public Gradient gradient = new Gradient();
    }
    #if UNITY_EDITOR
    [CustomEditor(typeof(GradientField))]
    public class GradientFieldEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            GradientField myTarget = (GradientField)target;
            //DrawDefaultInspector();

            /*public static Gradient GradientField (string label, Gradient value);*/
            myTarget.gradient = EditorGUILayout.GradientField(
                "Gradient",
                myTarget.gradient
                );
        }
    }
    #endif
}

GUI要素

GUIContent

アイコン画像、テキスト、マウスホバー時の表示テキストを指定します。

変数備考
imageTexture表示するアイコン画像
textstring表示するテキスト
(テキストのみの場合GUIContentの作成は不要です※1
tooltipstringGUI上にマウスを乗せたときに表示するテキスト

GUIContentの作成(GUIContentのコンストラクタ―)

//public GUIContent (string text); ※1
new GUIContent("Hello World")

//public GUIContent (Texture image);
//public GUIContent (string text, Texture image);
//public GUIContent (string text, string tooltip);
//public GUIContent (Texture image, string tooltip);
//public GUIContent (string text, Texture image, string tooltip);
//public GUIContent (GUIContent src);

※1 以下の2行は同じ機能になります。

"Hello World"
new GUIContent("Hello World")

空のGUIContent

GUIContent.none

GUIStyle

GUIStyleは、表示するGUIに適用する情報(色、配置、サイズ)を一括するものです。

GUIStyleの作成

GUIStyleはそのレイアウト毎に作成出来ます(TextAreaであればEditorStyles.textArea)。

好みにもよるかと思いますが、以下のようにして新たにスタイルを作成します。

//GUIStyle(textArea用)を作成
GUIStyle textAreaStyle = new GUIStyle(EditorStyles.textArea){
    //GUIStyleの変数欄を参照
    wordWrap = true
};
GUIStyle textAreaStyle = new GUIStyle(EditorStyles.textArea);
//GUIStyleの変数欄を参照
textAreaStyle.wordWrap = true

上記で新たに作成としていますが、下のような例で記述した場合、デフォルトのスタイルを上書きするため注意が必要です。

//デフォルトを上書きしてしまう。
//EditorStyles.textArea.wordWrap = true;

Rect

左上の隅からの描画開始座標と幅、高さを指定した長方形データを作成します。

Rectの作成(Rectのコンストラクタ―)

以下2つのコードは同じ意味(左上隅(0,0)から1920*1080の矩形を作成)です。

//public Rect (float x, float y, float width, float height);
// x     :基準(左上の隅)のx座標
// y     :基準(左上の隅)のy座標
// width :幅
// height:高さ
Rect rect = new Rect(0, 0, 1920, 1080);

既にVector2で位置やサイズを定義している場合は、以下のコードのように指定できます。

(例では新たに作成しているため意味はありません)

//public Rect (Vector2 position, Vector2 size);
//position:基準(左上の隅)の位置(x座標とy座標)
//size    :基準(左上の隅)の幅と高さ
Rect rect = new Rect(Vector2.zero, new Vector2(1920, 1080));

資料

参考

Unity EditorGUILayout スクリプトリファレンス

関連

コメント

タイトルとURLをコピーしました