Unity MenuItem でメニューを追加し静的関数を呼び出す(1)

前回は 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 ウィンドウにエラーログが出力されていてメニューにメニューアイテムは追加されません

Unity MenuItem でサブメニューまで指定しなかった場合のエラーログ
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 にサブメニューまで指定するとメニューバーに追加されました。

Unity MenuItem でitemNameにサブメニューまで指定するとメニューバーに追加されました。

TestMenuItem1 を選択すると、この MenuItem Attribute を付加した関数が呼び出され Console ウィンドウにログ出力されました。

Unity MenuItem で作成したメニューから呼び出した静的関数のログ出力

ショートカットキーの設定

itemName の末尾に %g などと設定するとショートカットキーを割り当てられます。 %g の場合は Ctrl + G をショートカットキーに設定できます。

[MenuItem("My/TestMenuItem1 %G")]
private static void TestMenuItem1()
{
    Debug.Log("TestMenuItem1 called.");
}
Unity MenuItem の itemName の末尾に %g などをつけるとショートカットキーを設定できます。

他にも以下のように 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” はホットキーとして認識されず、一方で "MyMenu/Do _g" は認識されます)

https://docs.unity3d.com/ja/2018.4/ScriptReference/MenuItem.html

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 ウィンドウ警告ログが出力されました。

Unity MenuItem にメンバ関数を割り当てた場合はメニューアイテムが追加されず警告ログが出力されました。

静的関数ではなく、メンバ関数を呼び出したい場合は前回紹介した ContextMenu Attribute を使うと良いでしょう。

public MenuItem (string itemName, bool isValidateFunction);

第 2 引数 bool isValidateFunctionValidation 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 翻訳)
isValidateFunction が true の場合、これは検証関数であり、同じ itemName でメニュー関数を呼び出す前に呼び出されます。

https://docs.unity3d.com/ja/2018.4/ScriptReference/MenuItem-ctor.html

メニューバーに表示するメニューアイテムの有効性を判定する関数が 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 引数 isValidateFunctiontrue の方は bool の戻り値を返します。これが false の場合、下図のように同一の itemName の My/TestMenuItem2 メニューアイテムはメニュー上で無効になり、選択できません

Unity MenuItem の Validation Function が false を返すと同一の itemName を持つメニューアイテムは非活性になります。

先ほどのコードの TestMenuItem2Validation 関数の戻り値を false から true に変えると、メニューアイテムが有効になり、押すと itemName が同一かつ isValidateFunction が falseTestMenuItem2 関数が呼び出されログ出力されました。

Unity MenuItem の Validation Function が true を返すと同一の itemName を持つメニューアイテムは活性状態になりました。
Unity MenuItem で作成したValidationFunctionがtrueを返したメニューから呼び出した静的関数のログ出力

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 つのメニューアイテムの中で先頭に表示され、線で仕切られました。

Unity MenuItem の priority = 100 にしたメニューアイテムが先頭に表示され線で仕切られました。

既定値が不明なので、適当に priority を変えていき順番が変動する分岐点を探しました。
その結果デフォルト値1000 だと思います。
ContextMenu では 1000000 と説明に書かれていたのですが、それぞれ違うデフォルト値のようです。
priority = 1000 にすると、宣言順に一番下に表示されて、線で仕切られました。

Unity MenuItem の priority = 1000 にしたメニューアイテムは、宣言順に一番下に表示され線で仕切られました。

priority = 999 にすると、一番上に表示されましたが、仕切り線は表示されませんでした。

Unity MenuItem の priority = 1000 にしたメニューアイテムは、宣言順に一番上に表示され仕切り線は表示されませんでした。

まとめ

今回は前回に引き続き、Unity エディタから関数を呼び出すためのメニューアイテムの追加を行う属性 MenuItem のコンストラクタ 3 つを紹介しました。
MenuItem にはさらに他の機能もあるため、次回も MenuItem Attribute について紹介します。

参照サイト Thank You!

 

コメント

Ads Blocker Image Powered by Code Help Pro

お願い - Ads Blocker Detected

このサイトは広告を掲載して運営しています。

ポップアップを閉じて閲覧できますが、よろしければ

このサイト内の広告を非表示にする拡張機能をオフにしていただけませんか?

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

We have detected that you are using extensions to block ads. Please support us by disabling these ads blocker.

タイトルとURLをコピーしました