この記事でのバージョン
Unity 2019.1.0b3
はじめに
先日、面白そうなエディタ拡張のツイートを見かけました。
In Unity 2019.1 alpha, there is a new EditorTools API.
— Alexander Ameye (@alexanderameye) January 22, 2019
I should probably find a good use for this, but for now it
works as a de-stressing tool that shows me kittens :)https://t.co/r2OLBxdAIj@unity3d #madewithunity #unitytips pic.twitter.com/RUejKZxINy
内容もさることながら、初めて見たタイプの拡張で驚いたので、
今回はこれを調べて試してみた感じの記事です。
EditorTool
先程のツイートはEditorToolという2019.1で追加された機能が使われています。
これは何かを実行するボタンを付けるというよりかは、
Unityにデフォルトで付いている移動や回転のように、
「Hierarchy上のオブジェクトを操作するような機能」を追加するのが主な使い方っぽいです。
例えばドキュメントに載っているサンプルだと
「オブジェクトを一方向だけに移動させる機能」を実装しています。
using System; using UnityEngine; using UnityEditor; using UnityEditor.EditorTools; // Tagging a class with the EditorTool attribute and no target type registers a global tool. Global tools are valid for any selection, and are accessible through the top left toolbar in the editor. [EditorTool("Platform Tool")] class PlatformTool : EditorTool { // Serialize this value to set a default value in the Inspector. [SerializeField] Texture2D m_ToolIcon; GUIContent m_IconContent; void OnEnable() { m_IconContent = new GUIContent() { image = m_ToolIcon, text = "Platform Tool", tooltip = "Platform Tool" }; } public override GUIContent toolbarIcon { get { return m_IconContent; } } // This is called for each window that your tool is active in. Put the functionality of your tool here. public override void OnToolGUI(EditorWindow window) { EditorGUI.BeginChangeCheck(); Vector3 position = Tools.handlePosition; using (new Handles.DrawingScope(Color.green)) { position = Handles.Slider(position, Vector3.right); } if (EditorGUI.EndChangeCheck()) { Vector3 delta = position - Tools.handlePosition; Undo.RecordObjects(Selection.transforms, "Move Platform"); foreach (var transform in Selection.transforms) transform.position += delta; } } }
より分かりやすいように、諸々のコメントを追加して
選択している全Transformを回転させるメニューを実装してみたのが以下のものになります。
ただし、Sceneビューを開いていないと使えません。(OnToolGUIが呼ばれない)
using UnityEngine; using UnityEditor; using UnityEditor.EditorTools; /// <summary> /// 選択している全Transformを回転させるメニュー /// </summary> [EditorTool("Rotate Tool")] class RotateTool : EditorTool { //アイコンの画像 [SerializeField] private Texture2D _toolIcon = null; //アイコンの画像や説明などGUI要素を設定するもの private GUIContent _content = null; //GUI要素を取得する用のプロパティ public override GUIContent toolbarIcon { get { return _content; } } //================================================================================= //初期化 //================================================================================= private void OnEnable() { //GUIの要素を作成 _content = new GUIContent() { image = _toolIcon, //アイコンの画像 text = "Rotate Tool", //メニューの名前 tooltip = "回転します!" //メニューの説明 }; } //================================================================================= //更新 //================================================================================= /// <summary> /// このツールを選択中に呼ばれ続けるメソッド(Sceneビューを開いてないと呼ばれない) /// </summary> public override void OnToolGUI(EditorWindow window) { //選択している全Transformを回転させる foreach (var transform in Selection.transforms) { transform.rotation = Quaternion.Euler(transform.rotation.eulerAngles + new Vector3(0, 5, 0)); } } }
なお、メニューの名前(Rotate Tool)は右クリックした時、
メニューの説明(回転します!)はカーソルを上に置いてる時に表示されます。
また、メニューは複数作る事も可能で、その場合は右クリックで使うものを選びます。
さらにEditorToolの第二引数を使う事で、
特定のコンポーネントが付いているオブジェクトを選択してる時にだけ使えるメニュー
というのも実装可能です。
//MeshFilterが付いてるオブジェクトを選択している時にだけ実行可能 [EditorTool("Vertex Tool", typeof(MeshFilter))]
ちなみにアイコン画像はInspectorから設定する事が出来ます。
//アイコンの画像 [SerializeField] private Texture2D _toolIcon = null;
EditorToolをボタン代わりに使う
EditorToolはOnActivateというメソッドで選択された瞬間が分かり、
(OnDeactivateで選択が解除された瞬間も分かる)
EditorTools.RestorePreviousToolを実行する事で前選択していたツールに戻す事も可能なので、
ボタン代わりにする事も出来ます。
例えば以下の記事の内容を使えば、
「Scenes in Buildの一番上に登録されているシーンから再生を開始するボタン」
(再生が終わったら再生前に開いていたシーンに戻る)
なんてものも作れます。(EditorPlayer.csも必要)
ちなみに、EditorTools.RestorePreviousToolはOnActivateとOnDeactivateからは使えません。
public override void OnActivate() { EditorTools.RestorePreviousTool(); }
InvalidOperationException: Attempting to set the active tool from EditorTool.OnActivate or EditorTool.OnDeactivate. This is not allowed.