(:3[kanのメモ帳]

個人ゲーム開発者kan.kikuchiのメモ的技術ブログ。月木更新でUnity関連がメイン。

Inspectorにメソッドを実行するボタンを追加する【Unity】【エディタ拡張】


このエントリーをはてなブックマークに追加

この記事でのバージョン
Unity 5.3.4f1 Personal


はじめに

特定のメソッドをInspectorから実行できるようにしておくと便利な場合は多々あると思いますが、

そんな時に一番楽なのはContextMenuだと思います。

//Inspectorの歯車アイコンにMethodという項目を追加、押すと下のメソッドが実行される
[ContextMenu("Method")]
private void Method () {
	
}

f:id:kan_kikuchi:20160711133319p:plain


ただ、使う側からするとパッと見でInspectorから実行できるメソッドがあるとは分からない

ので、少々不便かもしれません。


という事で今回はInspectorにメソッドを実行するボタンを追加する方法のご紹介です!


CustomEditor

Inspectorの表示を変えるにはEditorというクラスを継承したクラスを作成し、

CustomEditorという属性で拡張したいクラスを指定します。


例えばExampleScriptというクラスと、

そのExampleScriptのInspectorを拡張するExampleScriptEditor

作ってみると、以下のようになります。

using UnityEngine;

public class ExampleScript : MonoBehaviour {

}  
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ExampleScript))]//拡張するクラスを指定
public class ExampleScriptEditor : Editor {

  /// <summary>
  /// InspectorのGUIを更新
  /// </summary>
  public override void OnInspectorGUI(){

  }

}  

f:id:kan_kikuchi:20160712134745p:plain


上記のままだとOnInspectorGUIで何もしていないのでインスペクターには何も表示されません。


f:id:kan_kikuchi:20160712133006p:plain


base.OnInspectorGUIを書けば、継承元の元のOnInspectorGUIが実行されるので、

拡張しない場合と同じGUIが表示されます。

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ExampleScript))]//拡張するクラスを指定
public class ExampleScriptEditor : Editor {

  /// <summary>
  /// InspectorのGUIを更新
  /// </summary>
  public override void OnInspectorGUI(){
    //元のInspector部分を表示
    base.OnInspectorGUI ();
  }

}  

f:id:kan_kikuchi:20160712133222p:plain


ボタンを表示したい場合はGUILayout.Buttonをifの条件として使います。

ボタンが押されるとif内部の処理が実行される感じです。

using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ExampleScript))]//拡張するクラスを指定
public class ExampleScriptEditor : Editor {

  /// <summary>
  /// InspectorのGUIを更新
  /// </summary>
  public override void OnInspectorGUI(){
    //元のInspector部分を表示
    base.OnInspectorGUI ();

    //ボタンを表示
    if (GUILayout.Button("Button")){
      Debug.Log("押した!");
    }  
  }

}  

f:id:kan_kikuchi:20160712133623g:plain


さらに、targetで拡張している対象を取得できるので、

それを変換すれば対象のメソッドを実行できるようになります。

using UnityEngine;

public class ExampleScript : MonoBehaviour {

  //表示したログ、SerializeFieldを付ける事でInspectorに表示されるように
  [SerializeField]
  private string _log = "";

  /// <summary>
  /// _logを"ぷぅあぶりっく!"に変更してConsoleに表示
  /// </summary>
  public void PublicMethod(){
    _log = "ぷぅあぶりっく!";
    Debug.Log(_log);
  }

}  
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ExampleScript))]//拡張するクラスを指定
public class ExampleScriptEditor : Editor {

  /// <summary>
  /// InspectorのGUIを更新
  /// </summary>
  public override void OnInspectorGUI(){
    //元のInspector部分を表示
    base.OnInspectorGUI ();

    //targetを変換して対象を取得
    ExampleScript exampleScript = target as ExampleScript;

    //PublicMethodを実行する用のボタン
    if (GUILayout.Button("PublicMethod")){
      exampleScript.PublicMethod ();
    }

  }

}  

f:id:kan_kikuchi:20160712134104g:plain


privateなメソッドはそのままだと実行できないので、

SendMessageを使って実行すると楽かと思います。

なお、ExecuteInEditModeを使わないとエラーが出るので注意が必要です。

using UnityEngine;

[ExecuteInEditMode] //SendMessageでエラーが出ないように
public class ExampleScript : MonoBehaviour {

  //表示したログ、SerializeFieldを付ける事でInspectorに表示されるように
  [SerializeField]
  private string _log = "";

  /// <summary>
  /// _logを"ぷらいべーと!"に変更してConsoleに表示
  /// </summary>
  private void PrivateMethod(){
    _log = "ぷらいべーと!";
    Debug.Log(_log);
  }

}  
using UnityEditor;
using UnityEngine;

[CustomEditor(typeof(ExampleScript))]//拡張するクラスを指定
public class ExampleScriptEditor : Editor {

  /// <summary>
  /// InspectorのGUIを更新
  /// </summary>
  public override void OnInspectorGUI(){
    //元のInspector部分を表示
    base.OnInspectorGUI ();

    //targetを変換して対象を取得
    ExampleScript exampleScript = target as ExampleScript;

    //PrivateMethodを実行する用のボタン
    if (GUILayout.Button("PrivateMethod")){
      //SendMessageを使って実行
      exampleScript.SendMessage ("PrivateMethod", null, SendMessageOptions.DontRequireReceiver);
    }

  }

}  

f:id:kan_kikuchi:20160712134535g:plain


おわりに

楽に実装できるのはContextMenuなのですが、

使い勝手でみれば今回紹介した方法のがいいかと思います。

まぁ、状況に応じてといった感じでしょうか(:3っ)∋〜