今回はUnityのメニューに自作のメニューを表示させ、メニュー項目を選択した時に何らかの処理をさせたいと思います。
Unityのメニューとはエディターの上の方に表示されている部分ですね。
FileやEdit等をマウスでクリックしそれぞれのメニュー項目を選択して色々な処理を実行する事が出来ます。
そのUnityのメニューに自前のメニューを追加したり、メニューに項目を追加し、項目を選択した時に何らかの処理を実行させてみたいと思います。
エディターを拡張するスクリプトを配置するフォルダ
今回はUnityのエディターを拡張しますが、

MenuItemTestというスクリプトを作成しAssets/Editorフォルダに配置します。
1 2 3 4 5 6 7 8 | using UnityEngine; using System.Collections; using UnityEditor; public class MenuItemTest : MonoBehaviour { } |
Unityのメニューに項目を追加する方法
Unityのメニューに項目を追加するにはMenuItemアトリビュートをメソッドに追加します。
1 2 3 4 5 6 7 8 9 10 | public class MenuItemTest : MonoBehaviour { // 自前のメニューと項目を作成 [MenuItem("自前メニュー/項目1 %t", false, 1)] static void OutputConsole() { Debug.Log ("項目1が選択された"); } } |
MenuItemアトリビュートの第1引数には追加するメニューの名前と階層を設定しスペース文字の後にホットキー(ショートカットキー)の設定をします。
ホットキーを設定しない場合は記述する必要はありません。
%がCtrl(MacはCmd)、#がShift、&がAltキーに対応しており、↑のスクリプトの例でいくとCtrlキーを押しながらキーボードのTキーを押すとこの項目をマウスで選択した時と同じ動作をします。
%#&は組み合わせて設定する事が出来、%#&tとすればCtrl+Shift+Altを押しながらTキーを押す必要があります。
%#&以外にも特殊記号はありますが、この記事の最後にあるリンク先のUnityのスクリプトリファレンスで確認してください。
すでにあるショートカットキーと同じ設定にならないようにする必要があります。
第2引数ではbool型の値を設定し、第1引数で指定したメニューの階層で同じものがあった時にtrueを設定するとその項目が選択される前にtrueで設定したメソッドの処理を実行する事が出来ます。
正直なところ文章だけだとわからないので後で作成するサンプルで確認すると早いと思います・・・・(^_^;)
第3引数がメニュー項目の表示優先度の設定で番号が低いほど項目の上の方に表示されます。
この優先度の数値が前の項目の優先度より10大きくなった時は間に線が表示されるようになります。
自作のUnityメニューを作成するサンプル
Unityのメニューに項目を追加するやり方がわかったので、実際にサンプルを作成して実行してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | using UnityEngine; using System.Collections; using UnityEditor; public class MenuItemTest : MonoBehaviour { // 自前のメニューと項目を作成 [MenuItem("自前メニュー/項目1 %t", false, 1)] static void OutputConsole() { Debug.Log ("項目1が選択された"); } [MenuItem("自前メニュー/項目1 %t", true)] static bool IsValidate() { // 選択されているのがゲームオブジェクトか? return Selection.activeObject.GetType () == typeof(GameObject); } [MenuItem("自前メニュー/項目2 #t", false, 12)] static void OutputConsole2() { Debug.Log ("項目2が選択された"); } [MenuItem("自前メニュー/項目3 %#&t", false, 13)] static void OutputConsole3() { Debug.Log ("項目3が選択された"); } } |
メニューアイテムの名前は 自作メニュー というメニューがありその中にいくつかの項目を作成しました。
メソッドはクラスメソッド(staticを付ける)にします。
メソッド名は自分がわかりやすいように付けてください。
OutputConsoleとIsValidateメソッドのMenuItemの第1引数が同じですが、IsValidateの第2引数がtrueとなっているのでOutputConsoleより前に実行されます。
IsValidateでは選択されているオブジェクトがゲームオブジェクトであればtrueを返しOutputConsoleが実行出来ます。
それゲームオブジェクト以外を選択している時はfalseになるのでメニュー項目の項目1自体がグレー表示され選択出来ないようになります。
項目1と項目2の優先度は11違うので間に線が表示されるようになるはずです。
それぞれの項目にはホットキーを設定し、キーボードで処理を実行出来るようにしています。
それでは確認してみましょう。
↑のようになりました。
最初に項目1を選択しようとしますが、Assetsフォルダで選択しているオブジェクトがゲームオブジェクトでない為IsValidateメソッドでfalseが返されOutputConsoleは実行できません。
項目1と項目2の間には線が表示され、優先度の違いも確認出来ました。
動画の最後の方でCtrl+Shift+Alt+Tキーを押して項目3を実行しています。
最終的にTキーを押して処理を実行していますが、このTキーはすでに単独で押す事で他の動作をするショートカットキーとして登録されている為ゲームオブジェクト操作のアイコンが切り替わっています。
すでにあるメニューに項目を追加するサンプル
さきほどは自作のメニューの項目を作りましたが、次はすでにあるメニューに項目を追加するサンプルを作成してみます。
MenuItemTestスクリプトにメソッドを追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | // 自前メニューで新しいゲームオブジェクトを作成 [MenuItem("GameObject/MyMenu/自前のゲームオブジェクトを作成", false, 10)] static void CreateGameObject(MenuCommand command) { // 空のゲームオブジェクト作成 GameObject obj = new GameObject ("MyGameObject"); // ゲームオブジェクトの親の設定 GameObjectUtility.SetParentAndAlign (obj, command.context as GameObject); // Undo操作を加える(Ctrl+Zキーの操作に加える) Undo.RegisterCreatedObjectUndo (obj, "Create " + obj.name); // 初期位置を設定 obj.transform.position = Vector3.zero; // 作成したゲームオブジェクトを選択状態にする Selection.activeObject = obj; } // コンポーネントの取り付けとUndo登録 [MenuItem("GameObject/MyMenu/Rigidbodyの取り付け", false, 11)] static void AddComponentToObject() { // 選択しているゲームオブジェクトにRigidbody取りつけ // Selection.activeGameObject.AddComponent <Rigidbody>(); // Undo操作の追加+Rigidbodyの取り付け Undo.AddComponent <Rigidbody> (Selection.activeGameObject); } // 位置と角度の変更とUndo登録 [MenuItem("GameObject/MyMenu/位置と角度を変更", false, 12)] static void DefaultPosition(MenuCommand command) { // 選択しているゲームオブジェクトを取得 GameObject obj = Selection.activeGameObject; // この記述以降のtransformの変更をUndo出来るようにする Undo.RecordObject (obj.transform, "Change Position & Rotation"); obj.transform.position = new Vector3(10, 20, 30); obj.transform.rotation = Quaternion.Euler (60, 60, 60); } |
MenuItemアトリビュートを取りつけたメソッドではMenuCommand型の引数を受け取る事が出来ます。
ゲームオブジェクト作成項目
CreateGameObjectメソッドでは空のゲームオブジェクトを作成し、受け取ったMenuCommandのコンテキスト(選択中のゲームオブジェクト)を親に設定します。
Undo.RegisterCreatedObjectUndoでCtrl+Zキーを押した時に元に戻す事が出来るように設定します。
ここでUndo登録をしないとゲームオブジェクトを作成した後、Ctrl+Zキーを押してもゲームオブジェクトを作成した事を取り消せません。
Selection.activeObject = obj;
をする事で今作成したゲームオブジェクトを選択状態にしています。
Rigidbodyコンポーネント取りつけ項目
AddComponentToObjectでは
Undo.AddComponent
で選択中のゲームオブジェクトにRigidbodyコンポーネントを取りつけ、
Undoにも登録します。
Assetsフォルダにあるゲームオブジェクトを選択している時にも追加する事が出来ますが、選択中のオブジェクトがスクリプト等だった場合は当然エラーになります。
そこら辺のエラー対応は前のサンプルで使ったMenuItemの第2引数を使うといいかもしれません。
コメントにしているのはUndo登録をしないコンポーネントの取り付けです。
こちらの場合はコンポーネントの取り消しをCtrl+Zキーでは出来ません。
ゲームオブジェクトの位置と角度を設定する項目
DefaultPositionメソッドでは選択しているゲームオブジェクトの位置と角度を設定しています。
Undo.RecordObject (obj.transform, “Change Position & Rotation”);
でこの行以降で変更したobjのtransform情報に関する変更をUndoに登録します。
その為その後に実行するpositionとrotationの変更をCtrl+Zキーで元に戻す事が出来るようになります。
ゲームオブジェクトの作成と操作の実行
サンプルが出来たので実行してみましょう。
↑のようにメニュー項目からゲームオブジェクトの作成をし、Rigidbodyを取りつけ、位置と角度を変更した後Undo操作ですべての処理を取り消しています。
コンテキストメニュー項目の追加
Editorを継承して作成したクラスでコンテキストメニュー項目を追加する事が出来ましたが、今回はMenuItemで追加してみます。
MenuItemTestスクリプトにメソッドを追加します。
1 2 3 4 5 6 7 8 9 10 | // CharacterControllerのコンテキストメニューを追加 [MenuItem("CONTEXT/CharacterController/半径を3にする", false, 10)] static void Test(MenuCommand command) { // MenuCommand.contextをキャストしCharacterControllerを取得 var cCon = command.context as CharacterController; // CharacterControllerの半径を3にする cCon.radius = 3f; } |
MenuItemの第1引数をCONTEXTから始めるとインスペクタのコンポーネントのタイトルを右クリック、右上の歯車を押した時のメニュー項目を追加する事が出来ます。
今回のサンプルではCharacterControllerコンポーネントのコンテキストメニューを追加してます。
コンテキストメニュー項目を選択するとCharacterControllerのradiusが3に変更されます。
↑のように空のゲームオブジェクトにCharacterControllerを取りつけ右クリックでコンテキストメニューを表示し『半径を3にする』項目を選択すると、
CharacterControllerのradiusが3になりました。
終わりに
Unityのメニュー項目の追加は結構簡単に出来てしまいました!
Undoの登録の部分がちょっとわかり辛いところではありますが、通常のスクリプトを記述するのと大差はありません。
よく使う機能等はメニュー項目を作成し実行させるようにしておくと作業効率がよくなるかもしれませんね。
今回はわかりやすいように項目名を日本語表記していますが、通常はアルファベット表記の方がいいかもしれません。