[Unity3D][UnityEditor]EditorWindowの最小構成からボタン配置やらサブウィンドウの生成やら

[wp_ad_camp_1]

最小構成

ファイルをProjectのRootにEditorフォルダを作成し、その中に各種エディター的機能を使用するクラスを格納させておく必要がある。
(Asset/Editor/)
EditorはUnityEditorライブラリを使用し、ウィンドウを表示するのであればEditorWindowを継承させておく。
下のコードが最小構成。画面上部にメニュー項目が追加される。
それをクリックするとデバッグログに文字列を表示する。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class _OGKEditor : EditorWindow {

 [UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
 static void abcde(){
  Debug.Log("init"); 
 }

}

メニュー項目への表示は[]で囲われた範囲で、ディレクトリ階層を指定できる。
その次の行にあたるstatic関数が呼ばれる。この時の関数名は何でもいい。

Windowの出現

コードを次の様に書き換える。
変更した場所はDebag.Logから自身のクラスの型でEditorWindowによるGetWindowクラスで生成したwindowをキャストする。

public class _OGKEditor : EditorWindow {

 [UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
 static void abcde(){
  _OGKEditor window = (_OGKEditor)EditorWindow.GetWindow (typeof (_OGKEditor));
 }

 void OnGUI(){
  if(GUILayout.Button("button")){
   //ボタン押した時の動作を記述
  }
 }
}

次の関数がウィンドウ生成している。サンプルは格納後に即座に開放して参照を切っているが、生成はちゃんとなされているのでOnGUI()で指定した動作は行われる。
EditorWindow.GetWindow( typeof() );
このウィンドウだけでウィンドウそのものを生成することはできるけど、各種初期設定をすることになるので、自身の型で参照を保ったまま、各種プロパティを変更しておく方が望ましい。

EditorWindowオブジェクトのプロパティやメソッドは次に一覧されている。
http://docs.unity3d.com/Documentation/ScriptReference/EditorWindow.html

プロパティ一覧

  • wantsMouseMove
    • BOOL
    • マウスイベントを取得するか否かを指定。
  • autoRepaintOnSceneChange
  • minSize
    • Vector2
    • ウィンドウの最小サイズ
  • maxSize
    • Vector2
    • ウィンドウの最大サイズ
  • title
    • string
    • ウィンドウのタブ上に表示される文字列
  • position
    • Rect
    • ウィンドウの初期位置と初期サイズ

試しに追加した初期値

 static void abcde(){
  _OGKEditor window = EditorWindow.GetWindow (typeof (_OGKEditor));
  window.minSize = new Vector2(300f,300f);
  GUIContent content = new GUIContent("__abcde__");
  window.ShowNotification(content);
  window.title = "org editor";
  window.position = new Rect(300f,300f,300f,300f);
 }

Window生成直後にNoticeを表示

初期化関数であるabcd()を次の様に追加してみる。

 static void abcde(){
  _OGKEditor window = EditorWindow.GetWindow (typeof (_OGKEditor));
  window.minSize = new Vector2(300,200);
  GUIContent content = new GUIContent("__abcde__");
  window.ShowNotification(content);
 }

すると、ウィンドウ生成直後に適当なサイズで文字列を表示できる。

UnityEditorWindowWithNotice

この文字列は数秒で消えるので注意喚起とか、複数のウィンドウを開いたり閉じたりさせる場合に現在のプレファブ名だとかを表示されることで、意識的に編集できるようになり、ヒューマンエラーを防止できる。
開いた時でなくても、windowに参照さえあれば次の様に記述してイベント事に確認したいことを表示することができる。

  GUIContent content = new GUIContent("Do not take my potato!");
  window.ShowNotification(content);

表示できるのはイベントが発生したときや独自の通知を受けた時。

EditorWindowクラス側が用意しているイベントは次の通り。

  • OnGUI Implement your own editor GUI here.
    • 描画されたときに走る。
    • ウィンドウ内のレイアウトを切ったりするのもここ。
  • Update Called 100 times per second on all visible windows.
    • 表示中のウィンドウは漏れなく秒間100回呼び出される。
  • OnInspectorUpdate OnInspectorUpdate is called at 10 frames per second to give the inspector a chance to update
    • 秒間10回の頻度で更新されるインスペクタ上のUpdate関数。
  • OnDestroy OnDestroy is called when the EditorWindow is closed.
    • windowを閉じた時に呼ばれる。
  • OnSelectionChange Called whenever the selection has changed.
    • SceneやHierarchy内でクリックする等して選択が変更される度に呼ばれる。
    • ウィンドウとは無関係で呼ばれる。
    • Selectionクラスから色々取得できる。
  • OnFocus Called when the window gets keyboard focus.
  • OnLostFocus Called when the window loses keyboard focus.
    • アクティブになるとOnFocusが、非アクティブになるとOnLostFocusが呼ばれます。
  • OnHierarchyChange Called whenever the scene hierarchy has changed.
    • ヒエラルキーが変わったら呼ばれる。ヒエラルキーの変動で読み直しすべきデータがあるのであれば読み直しを記述する。
  • OnProjectChange Called whenever the project has changed.
    • プロジェクトが変わったら呼ばれる。
    • データを読み込んで何かを表示しているのであれば、ここに読み直しの処理等を記述する。

OnSelectionChangeのサンプル

次のコードで選択しているオブジェクトのIDをずらっと表示できる。
オブジェクトを選択する都度呼ばれる。

 void OnSelectionChange(){
  foreach(int a in Selection.instanceIDs ){
   Debug.Log("id = "+ a); 
  }
 }

http://docs.unity3d.com/Documentation/ScriptReference/EditorWindow.OnSelectionChange.html

ウィンドウからさらにウィンドウを出現させる

サブウィンドウ用にクラス内クラスを用意。

 public class SubWindow: EditorWindow
 {
  public static SubWindow WillAppear(){
   
   SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
   window.minSize = new Vector2(50f,100f);
   window.title = "SubWindow";
   return window;
  }
  void OnGUI(){
   GUILayout.Label("SubWindow Here"); 
  }
 }

で、親ウィンドウ側にはボタンから呼び出す様に次ぎのように記述を変更、追加する。

 void OnGUI(){
  if(GUILayout.Button("button"+num)){
   ButtonPushed();
  }
 }
 void ButtonPushed(){
  ++num;
  subWindow = SubWindow.WillAppear();
 }

SubWindowクラスに定義したWillAppearを呼び出す。
呼び出されたサブクラス側はサイズやらタイトルが差し替えられて以下のように出現する。

!!

うごごご。動かない。
エラー内容は次のとおり。

Instance of SubWindow couldn’t be created because there is no script with that name.

SubWindowのインスタンスは作られませんでしたよ。なぜならその名前でかかれたスクリプトなんざねーからだ!

サブウィンドウは別ファイルで定義

先に記述したクラス内クラスを独立したクラスとして定義しなおす。
次の様に適当なEditorWindow継承クラスを定義して、Editorディレクトリ下に入れておく。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class SubWindow: EditorWindow
{
 public static SubWindow WillAppear(){
  
  SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
  window.minSize = new Vector2(50f,100f);
  window.title = "SubWindow";
  return window;
 }
 void OnGUI(){
  GUILayout.Label("SubWindow Here"); 
 }
}

UnityEditorWindowWithSubWindow

と、今日はここまで。

ゲームの作り方  Unityで覚える遊びのアルゴリズム

おまけ

自身を無限に生成しつづけるブラクラみたいのつくれないかな?と思ったのだけれどEditorWindowクラスは代々シングルトンみたいです。
以下のサンプルはボタン付きウィンドウを表示してボタンが押されると自身を生成するもの。
生成されたとたん、もともとあったウィンドウは削除される。
解りやすくする為に生成される都度、位置を変更している。

using UnityEngine;
using UnityEditor;
using System.Collections;

public class _BrowserCrasher : EditorWindow {

 public _BrowserCrasher parent;

 [UnityEditor.MenuItem("Custom/OHGAKI/bracra")]
 public static void init()
 {
  _BrowserCrasher window = initWithPosition(new Vector2(100f,100f));
  window.Show();
 }

 public static _BrowserCrasher initWithPosition(Vector2 pos)
 {
  _BrowserCrasher window = EditorWindow.GetWindow(typeof(_BrowserCrasher));
  window.position = new Rect( pos.x+10f,pos.y+10f,100f,100f);
  return window;
 }

 void OnGUI()
 {
  if(GUILayout.Button("button"))
  {
   _BrowserCrasher window = initWithPosition(new Vector2( this.position.x ,this.position.y));
   window.parent = this;
   
  }
 }
}

サンプル全容

メインウィンドウ

using UnityEngine;
using UnityEditor;
using System.Collections;
using System.Collections.Generic;

public class _OGKEditor : EditorWindow {
	
	private int num = 0;
	private SubWindow subWindow;
	
	[UnityEditor.MenuItem("Custom/OHGAKI/EdtiorTest")]
	static void abcde(){
		_OGKEditor window = EditorWindow.GetWindow (typeof(_OGKEditor));
		window.minSize = new Vector2(300f,300f);
		window.title = "org editor";
		window.position = new Rect(300f,300f,300f,300f);
		GUIContent content = new GUIContent("__abcde__");
		window.ShowNotification(content);
	}
	
	void OnGUI(){
		if(GUILayout.Button("button"+num)){
			ButtonPushed();
		}
	}
	void ButtonPushed(){
		++num;
		subWindow = SubWindow.WillAppear();
	}
	
	
	//On!!
//	void OnSelectionChange(){
//		foreach(int a in Selection.instanceIDs ){
//			Debug.Log("id = "+ a);	
//		}
//	}
//	
//	void OnFocus(){
//		Debug.Log("OnFocus");
//	}
//	void OnLostFocus(){
//		Debug.Log("OnLostFocus");
//	}
	
	
}

サブウィンドウ

using UnityEngine;
using UnityEditor;
using System.Collections;

public class SubWindow: EditorWindow
{
	public static SubWindow WillAppear(){
		
		SubWindow window = (SubWindow)EditorWindow.GetWindow(typeof(SubWindow));
		window.minSize = new Vector2(50f,100f);
		window.title = "SubWindow";
		return window;
	}
	void OnGUI(){
		GUILayout.Label("SubWindow Here");	
	}
}

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です