読者です 読者をやめる 読者になる 読者になる

LotosLabo

プログラミング技術とか気になった情報を載せていきます

UnityのEditor拡張触ってみた

Unity

はじめに

                 Editor拡張とは何か…?



UnityEditorに自分自身で新たに機能を追加すること。
例えばUnity画面のメニューに項目を追加したり、インスペクターの表示を変えたり…

まさに自分の好きなように、便利にするためのものです。

はっきり言って、 楽しいです!!!


ウインドウ表示

Unity画面上部のメインメニューにアイテムを追加して、
追加したアイテムをクリックすると新しいWindowを表示する処理をやってみます。

まずEditor拡張するための準備を行います。


(1)Assets以下にEditorフォルダを作成
(2)Editorフォルダの中にEditor拡張用のプログラムを作成します
(3)例:SampleEditor.cs(C#)ファイルを作成

※EditorフォルダにEditor拡張用のプログラムを置かないと、
Build時にエラーを吐いて止まってしまいます。


以下、SampleEditor.csのコードとなります。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class SampleEditor : EditorWindow {

  /// <summary>
  /// メニューにアイテムを追加し、ウインドウを開く.
  /// </summary>
  [MenuItem("SampleEditor/ShowWindow")]
  private static void ShowWindow()
  {
    // ウインドウの取得.
    var window = EditorWindow.GetWindow(typeof(SampleEditor));

    // ウインドウの表示.
    window.Show();
  }
}


出力結果
f:id:lo25131:20150928002932j:plain


【解説】

UnityEditorの機能を使うため、
using UnityEditor; を追加する。

クラス自体にEditorWindowを継承する。

[MenuItem("タブ名/アイテム名")]
でメインメニューにアイテムを追加し、そのすぐ下のメソッドに、アイテム押下時の機能を書く。
(既存のタブ名を指定するとそのタブにアイテムが追加されます。)

アイテムの機能のメソッドはstaticのみ受け付けます。アイテムが選択できない状態になります。


EditorのUIの表示

UIの表示を行っていきます。
今回は以下のUIを配置していきます。

  • ラベル
  • テキストフィールド
  • ボタン
  • スクロールビュー
  • 色指定
  • スタイルの指定


UIはOnGUIに書いていきます。
以下コードとなります。


【テキスト系UI】

/// <summary>
/// テキストフィールド用変数.
/// </summary>
private string m_textField = string.Empty;

void OnGUI()
{
 // ラベルの作成.
  EditorGUILayout.LabelField("Hello World");

  // 値付きラベルの作成.
  EditorGUILayout.LabelField("Hello World", "Guten Tag");
  
  // スタイルの作成.
  GUIStyle guiStyle = new GUIStyle();

  // テキストカラーを指定.
  guiStyle.normal.textColor = Color.red;

  // スタイル指定ラベル.
  EditorGUILayout.LabelField("Hello World", "Guten Morgen", guiStyle);
  
  // テキストフィールド.
  EditorGUILayout.TextField("Hello World", m_textField);
}


<出力結果>
f:id:lo25131:20150928003021j:plain



【ボタン系UI】

/// <summary>
/// ボタン名1.
/// </summary>
private const string BTN_NAME1 = "button1";

/// <summary>
/// ボタンサイズ1.
/// </summary>
private Vector2 m_btnSize1 = new Vector2(100,20);

void OnGUI()
{
  // ボタン(ボタン名、ボタンサイズ横、ボタンサイズ縦).
  if (GUILayout.Button(BTN_NAME1, GUILayout.Width(m_BtnSize1.x), GUILayout.Height(m_BtnSize1.y)))
  {
  // 以下処理.
    Debug.Log("Hello World");
  }
}

ボタンの作成は少々面倒ですが、if文として作成します。

<出力結果>
f:id:lo25131:20150928003040j:plain



【スクロールビュー】

/// <summary>
/// スクロールビューポジション.
/// </summary>
private Vector2 scrollView_Position;

/// <summary>
/// スクロールビューサイズ.
/// </summary>
private Vector2 scrollView_Size = new Vector2(500, 100);

/// <summary>
/// スクロールビュー内ラベル.
/// </summary>
private string scrollView_Label = string.Empty;

void OnGUI()
{
  // スクロールビューの作成.
  EditorGUILayout.BeginScrollView(scrollView_Position, GUI.skin.box, GUILayout.Width(scrollView_Size.x), GUILayout.Height(scrollView_Size.y));
  
  // スクロールビュー内のラベル.
  GUILayout.Label(scrollView_Label);

  // スクロールビューの終了.
  EditorGUILayout.EndScrollView();
}

void Test()
{
  // スクロールビュー内のラベルに追加.
  scrollView_Label += "\n" + "追加";

  // スクロールバーを最下部まで送る.
  scrollView_Position.y = Mathf.Infinity;
}

スクロールバーを送るには、scrollView_Positionのx、yを調整します。
今回は一番下まで自動で送りたいのでMathf.Infinityという無限を指定しています。


<出力結果>
f:id:lo25131:20150928003058j:plain



【スタイル系】

/// <summary>
/// ボタンアクティブフラグ.
/// </summary>
private bool is_btn_active = false;

/// <summary>
/// タブボタンアクティブフラグ.
/// </summary>
private bool is_tabBtn_active = false;

void OnGUI()
{
   // 横並びにする.
   EditorGUILayout.BeginHorizontal();

      // ラベルの配置.
      EditorGUILayout.LabelField("Hello World1");
      EditorGUILayout.LabelField("Hello World2");
      EditorGUILayout.LabelField("Hello World3");

   // スタイルの終了.
   EditorGUILayout.EndHorizontal();

   // スペースを空ける.
   EditorGUILayout.Space();

   // ボタンの非アクティブ(灰色になり押下不可).
   EditorGUI.BeginDisabledGroup(is_btn_active);

      // ボタン配置.
      if (GUILayout.Button("ボタン1", GUILayout.Width(300), GUILayout.Height(50)))
      {
          Debug.Log("Hello World");
      }

   // グループの終了.
   EditorGUI.EndDisabledGroup();
}

// タブボタンの表示・非表示.
[MenuItem("SampleEditor/Show1", is_tabBtn_active)]
public static void Show1()
{
}

private static void Test()
{
 // タブボタンの表示.
 is_tabBtn_active = true;
}
  

メインメニューのアイテムに追加したタブボタンも表示・非表示の設定が行えます。

<出力結果>
f:id:lo25131:20150928003115j:plain


ボタン押下時にファイル選択ボタンを開く


ボタン押下時にファイルブラウザを開き、そこで選択したファイルのパスをラベルに表示させます。

/// <summary>
/// ファイルパス.
/// </summary>
private string m_filePath = string.Empty;

void OnGUI()
{
   // ファイルブラウザを開く(第1引数:ブラウザ名、第二引数:最初に開くパス、第三引数:選択可能なファイル).
   string filePath = EditorUtility.OpenFilePanel
                         (
                            "Select File",
                            Application.dataPath,
                            "txt"
                         );

  // ファイルが選択されていない時.
 if(filePath.Length <= 0)
  {
    return;
  }

  m_filePath = filePath;
 
 EditorGUILayout.LabelField("Hello World", m_filePath);
}

まとめ

Editor拡張はやればやるほど楽しくなり、それに便利になります。
しかし、Unity内でできることは限られているので、無理にUnity内で済ませようとしないことも大切です。

今回はEditorUtilityクラスを主に用いてEditor拡張を紹介しましたが、インスペクターのUIを変える、
Attributeというものもあります。

例えば普段使っている、[SerializedField]もAttributeです。

それでは、よいEditor拡張ライフを。