前回は ContextMenu Attribute を追加することで、Unity エディタの Inspector ウィンドウのプルダウンメニューアイテムを追加し、そこからメンバ関数を呼び出す手順を紹介しました。
今回は Unity エディタのメニューバーにメニューアイテムを追加できる MenuItem Attribute について紹介します。
前回も説明しましたが、 ContextMenu はメンバ関数を呼び出し、MenuItem は静的関数を呼び出す違いがあります。
※ Unity は 2021.3.14f1 です。
MenuItem Attribute
MenuItem Attribute をスクリプトの関数に付加することで、メニューバーの最上位のメニューアイテムの段階からメニューアイテムを追加できます。
コンテキストメニューにもメニューアイテムを追加できます。
MenuItem Attribute は 3 つのコンストラクタを持つので順に紹介します。
public MenuItem (string itemName);
第 1 引数 string itemName はメニューバーに追加するメニューアイテムの名前です。
前回紹介した ContextMenu Attribute の itemName と同じように「/」で区切って階層を表現できます。
ContextMenu ではメニューアイテム名だけで問題ありませんでした。
しかし、 MenuItem Attribute はメニューバーにメニューアイテムを追加するため、サブメニューまで指定する必要があります。
サブメニューがないメニューアイテム名だけのコードを書いて見ます。
[MenuItem("TestMenuItem1")]
private static void TestMenuItem1()
{
Debug.Log("TestMenuItem1 called.");
}
Unity エディタに戻ると、Console ウィンドウにエラーログが出力されていてメニューにメニューアイテムは追加されません。
Ignoring menu item TestMenuItem1 because it is in no submenu!
MenuItem Attribute を使うと、メニューバーの File, Edit, Component などのようにトップのメニュー群にも新しいメニューアイテムを追加できますが、その更に下にサブメニューを指定する必要があります。
MenuItem 属性の itemName に「My/」を追加しました。
[MenuItem("My/TestMenuItem1")]
private static void TestMenuItem1()
{
Debug.Log("TestMenuItem1 called.");
}
MenuItem の itemName にサブメニューまで指定するとメニューバーに追加されました。
TestMenuItem1 を選択すると、この MenuItem Attribute を付加した関数が呼び出され Console ウィンドウにログ出力されました。
ショートカットキーの設定
itemName の末尾に %g などと設定するとショートカットキーを割り当てられます。 %g の場合は Ctrl + G をショートカットキーに設定できます。
[MenuItem("My/TestMenuItem1 %G")]
private static void TestMenuItem1()
{
Debug.Log("TestMenuItem1 called.");
}
他にも以下のように shift, Alt キーなどと組み合わせたり、単一の文字ならば _g などで指定できます。
いくつかの特殊記号はホットキーとしてサポートされていて、例えば “#LEFT” は Shift + 左矢印キーにマッピングされます。このようにサポートされているキーは上下左右の矢印キー、F1 ~ F12 キー、Home キー、End キー、Page Up キー、Page Down キーです。( LEFT, RIGHT, UP, DOWN, F1 .. F12, HOME, END, PGUP, PGDN )
ホットキーの文字列の前にスペース文字を含める必要があります( “MyMenu/Do _g” はホットキーとして認識されず、一方で
https://docs.unity3d.com/ja/2018.4/ScriptReference/MenuItem.html"MyMenu/Do _g"
は認識されます)
These are the supported keys (can also be combined together):
- % – CTRL on Windows / CMD on OSX
- # – Shift
- & – Alt
- LEFT/RIGHT/UP/DOWN – Arrow keys
- F1…F2 – F keys
- HOME, END, PGUP, PGDN
Character keys not part of a key-sequence are added by adding an underscore prefix to them (e.g: _g for shortcut key “G”).
https://learn.unity.com/tutorial/editor-scripting
メンバ関数は本当に呼び出せないのか?
ちなみに、さきほどのコードの関数宣言から static を取り除きメンバ関数にすると、 Unity エディタのメニューバーに My/TestMenuItem1 メニューアイテムは追加されず、Console ウィンドウに警告ログが出力されました。
静的関数ではなく、メンバ関数を呼び出したい場合は前回紹介した ContextMenu Attribute を使うと良いでしょう。
public MenuItem (string itemName, bool isValidateFunction);
第 2 引数 bool isValidateFunction は Validation Function の場合は true を指定します。
デフォルト値は false です。
公式サイトの説明とその翻訳です。
If isValidateFunction is true, this is a validation function and will be called before invoking the menu function with the same itemName.
(Google 翻訳)
https://docs.unity3d.com/ja/2018.4/ScriptReference/MenuItem-ctor.html
isValidateFunction が true の場合、これは検証関数であり、同じ itemName でメニュー関数を呼び出す前に呼び出されます。
メニューバーに表示するメニューアイテムの有効性を判定する関数が Validation Function のようです。
まずは具体的なコードを見てください。
// 同じ itemName を持つメニューアイテムの有効性を判定します。戻り値が false だと対応するメニューアイテムは無効の表示になります。
[MenuItem("My/TestMenuItem2", true)]
private static bool TestMenuItem2Validation()
{
return false;
}
// TestMenuItem2Validation 関数で true の場合のみ選択可能なメニューアイテムです。 false の場合は無効なので関数を呼び出せません。
[MenuItem("My/TestMenuItem2", false)]
private static void TestMenuItem2()
{
Debug.Log("TestMenuItem2 called");
}
MenuItem の第 1 引数 itemName はどちらも同じメニューアイテムのパスです。
第 2 引数 isValidateFunction が true の方は bool の戻り値を返します。これが false の場合、下図のように同一の itemName の My/TestMenuItem2 メニューアイテムはメニュー上で無効になり、選択できません。
先ほどのコードの TestMenuItem2Validation 関数の戻り値を false から true に変えると、メニューアイテムが有効になり、押すと itemName が同一かつ isValidateFunction が false の TestMenuItem2 関数が呼び出されログ出力されました。
isValidateFunction を用いる場合は true の方の関数 (Validation Function) は bool を戻り値にして、メニューアイテムの有効性を判断して返します。
itemName が同じで isValidateFunction が false の関数は、有効な状態のメニューアイテムが選択されたときに呼び出されます。
public MenuItem (string itemName, bool isValidateFunction, int priority);
第 3 引数 int priority はメニューに表示する順番に影響します。
値が小さいほどメニューの上位にメニューアイテムが表示されます。
// priority の値が小さいほどリストの上位に優先されてメニューアイテムが表示されます。
[MenuItem("My/TestMenuItem3", false, 100)]
private static void TestMenuItem3()
{
Debug.Log("TestMenuItem3 called.");
}
priority を 100 にすると My の中の 3 つのメニューアイテムの中で先頭に表示され、線で仕切られました。
既定値が不明なので、適当に priority を変えていき順番が変動する分岐点を探しました。
その結果デフォルト値は 1000 だと思います。
ContextMenu では 1000000 と説明に書かれていたのですが、それぞれ違うデフォルト値のようです。
priority = 1000 にすると、宣言順に一番下に表示されて、線で仕切られました。
priority = 999 にすると、一番上に表示されましたが、仕切り線は表示されませんでした。
まとめ
今回は前回に引き続き、Unity エディタから関数を呼び出すためのメニューアイテムの追加を行う属性 MenuItem のコンストラクタ 3 つを紹介しました。
MenuItem にはさらに他の機能もあるため、次回も MenuItem Attribute について紹介します。
参照サイト Thank You!
- Unity のリアルタイム開発プラットフォーム | 3D/2D、VR/AR のエンジン
- UnityEditor.MenuItem – Unity スクリプトリファレンス
- MenuItem-MenuItem – Unity スクリプトリファレンス
- ContextMenu-ContextMenu – Unity スクリプトリファレンス
- Editor Scripting – Unity Learn
コメント