Unityエディター拡張 - Menu Item

確認済のバージョン: 4.5

-

難易度: 中級

Unity エディターには、見た目も挙動もビルトインのメニューのように見えるカスタムメニューを追加することができます。これは、エディターのユーザインターフェースから直接アクセスが必要な、頻繁に使う機能をメニューに加えるのにとても役立ちます。 ここでは、Unity エディターで新しいメニュー項目を作成する方法を説明しながら、トピックごとに実用的な使用例を紹介します。

メニュー項目の追加

最上位のツールバーに新しいメニュー項目を加えるには、エディタースクリプトを作成します (プロジェクト内のどこでもよいので Editor と名付けたフォルダー下に置きます)。メニュー項目はスクリプトコード内で、MenuItem 属性を使い静的メソッドとして作成されます。

例えば、チームや会社でよく使用するオプション用に、新しい「ツール」 (または、社名やチーム名のついた最上位のメニュー) を追加することは一般によくあることです。

こちらは、オプション (すべての PlayerPrefs データの削除) が 1 つついた新しい Tools メニューを追加する例です。

Code snippet

using UnityEngine;
using UnityEditor;
 
public class MenuItems
{
    [MenuItem("Tools/Clear PlayerPrefs")]
    private static void NewMenuOption()
    {
        PlayerPrefs.DeleteAll();
    }
}

ここでは新しいエディターメニュー Tools を作成し、メニュー項目 Clear PlayerPrefs をその下に配置します。

Alt MenuItems 01

既存のメニューの下に新しいメニュー項目を作成することも可能です (例えば Window メニューの下など)。また、構成や効率を向上させるために複数のレベルのメニューを作成することも可能です (推奨)。

Code snippet

using UnityEngine;
using UnityEditor;
 
public class MenuItemsExample
{
    // 既存のメニュー下に新しいメニュー項目を追加
 
    [MenuItem("Window/New Option")]
    private static void NewMenuOption()
    {
    }
 
    // 入れ子になった複数のレベルを持つメニュー項目を追加
 
    [MenuItem("Tools/SubMenu/Option")]
    private static void NewNestedOption()
    {
    }
}

上のコートで以下のメニュー項目が追加されます。

Alt MenuItems 01

ホットキー

パワーユーザーや上級者がより素早く作業するために、新しいメニュー項目にホットキー (ショートカットキーの組み合わせで、自動的に機能を開始します) を割り当てることが可能です。

以下は、使用可能なキーです (組み合わせも可能です)。左はスクリプト内表記、右が実際のキー。

  • % – CTRL (Windows) または command (OSX)

  • # – Shift

  • & – Alt キー

  • LEFT/RIGHT/UP/DOWN – 方向キー

  • F1…F2 – F キー

  • HOME, END, PGUP, PGDN – HOME、END, PageUp, PageDown

連続したキーの一部としてでなく、単独で文字キーを使う場合は、アンダースコアをプレフィックスとして付けて表します (例えば、ショートカットキー G は _g と表します)。

以下の例のように、ホットキー文字の組み合わせはメニュー項目のパスの最後に、1 スペースあけて加えます。

Code snippet

// ホットキー CTRL-SHIFT-A の新しいメニュー項目を追加
 
[MenuItem("Tools/New Option %#a")]
private static void NewMenuOption()
{
}
 
// ホットキー CTRL-G の新しいメニュー項目を追加
 
[MenuItem("Tools/Item %g")]
private static void NewNestedOption()
{
}
 
// ホットキー G の新しいメニュー項目を追加
[MenuItem("Tools/Item2 _g")]
private static void NewOptionWithHotkey()
{
}

ホットキーがあるメニュー項目では、キーの組み合わせが表示されます。例えば、上のコードは以下のようなメニュー表示になります。

Alt MenuItems 03

注意: 同じホットキーを複数の項目に重複して割り当ててもチェック機能は働きません。そのため、ホットキーを重複して定義した場合は、1 つの項目だけが起動します。

特殊パス

以下の例のように、MenuItem 属性に渡されるパスによって、どの最上位メニューの下に新しい項目が置かれるかが決まります。

Unity には、コンテキストメニュー (右クリックメニュー) と同様に働く特殊パスがいくつかあります。

  • Assets – 項目は Assets メニューの下に置かれます。同様に、プロジェクトビュー内で右クリックでも表示されます。

  • Assets/Create – プロジェクトビューで Create ボタンをクリックすると、項目が表示されます (プロジェクトに加える可能性のある新しいタイプを追加するのに便利)。

  • CONTEXT/ComponentName – 指定したコンポーネントのインスペクター内で右クリックすると表示されます。

以下は、特殊パスの使い方を示しています。

Code snippet

// プロジェクトビューのアセット上で右クリックしてアクセスできる新しいメニュー項目を追加
 
[MenuItem("Assets/Load Additive Scene")]
private static void LoadAdditiveScene()
{
    var selected = Selection.activeObject;
    EditorApplication.OpenSceneAdditive(AssetDatabase.GetAssetPath(selected));
}
 
// Adding a new menu item under Assets/Create
 
[MenuItem("Assets/Create/Add Configuration")]
private static void AddConfig()
{
    // Create and add a new ScriptableObject for storing configuration
}
 
//  RigidBody コンポーネントで右クリックしてアクセスできる新しいメニュー項目を追加
 
[MenuItem("CONTEXT/Rigidbody/New Option")]
private static void NewOpenForRigidBody()
{
}

上のコードによって、以下の新しいメニュー項目が表示されます。

Alt MenuItems 04 Assets (Project ウィンドウ) 右クリックメニュー

Alt MenuItems 05 Asset の CREATE ボタンから可能な新しい選択肢

Alt MenuItems 06 RigidBody コンポーネントの新しいコンテクストメニュー

検証

メニュー項目のいくつかは、あるコンテキストのみで正しく作動し、そうでない場合は、使用できません。使用するコンテキストによってメニューの項目を有効、または、無効にするには、検証 (vidation) のメソッドを加えます。

Validation メソッドは MenuItem 属性を使い、検証の引数に true を渡す静的メソッドです。

Validation メソッドはそれが検証しようとしているメニューと同じパスを持ち、 bool 値を返してメニュー項目が有効か否かを判断します。

例えば、Validation メソッドは、プロジェクトビューで Texture アセットだけに右クリックメニューを加えるために使用することができます。

Code snippet

[MenuItem("Assets/ProcessTexture")]
private static void DoSomethingWithTexture()
{
}
 
// 1 番目の引数には同じパス、2 番目の引数には true を渡すことに注意
[MenuItem("Assets/ProcessTexture", true)]
private static bool NewMenuOptionValidation()
{
    // 選択したオブジェクトが Texture2D の場合は true を返します (そうでない場合は、メニュー項目は無効になります)
    return Selection.activeObject.GetType() == typeof(Texture2D);
}

このようにすると、プロジェクトビューでテクスチャでない限り、メニュー項目のオプションは無効 (グレイアウト) になります。

Alt MenuItems 07

Priority (優先度) によるメニューの順番の制御

priority (優先度) はメニュー項目に指定する番号で (MenuItem 属性に渡されます)、ルートメニュー以下のメニュー項目の順番を制御します。

さらに、メニュー項目は指定された優先度の値に基づいて、自動的に、値 50 ごとに区切ってグループ分けされます。

Code snippet

[MenuItem("NewMenu/Option1", false, 1)]
private static void NewMenuOption()
{
}
 
[MenuItem("NewMenu/Option2", false, 2)]
private static void NewMenuOption2()
{
}
 
[MenuItem("NewMenu/Option3", false, 3)]
private static void NewMenuOption3()
{
}
 
[MenuItem("NewMenu/Option4", false, 51)]
private static void NewMenuOption4()
{
}
 
[MenuItem("NewMenu/Option5", false, 52)]
private static void NewMenuOption5()
{
}

以下の例では、指定された優先度をもとに 2 グループのアイテムで構成されたメニューが作成されます。

Alt MenuItems 08

既存の Unity メニューにメニューアイテムを追加したり整理したりする必要がある場合は、少し「推量」を働かせることが必要です。たいていのビルトインのメニューアイテムが優先度を使用しています。他の方法としては、Reflector などのツールを使い、エディターのメニューのいくつかを作成している Unity の内部的ソースコード (UnityEditor.CreateBuildInWindows など) を見ることです。

関連クラス

以下は、新しいメニューアイテムの追加に関連するいくつかの追加クラスです。

MenuCommand

インスペクターに新しいメニューアイテムを加えるときに (上の説明のように "CONTEXT/Component" を使用して)、実際のコンポーネントへの参照の取得が必要な場合があります (例えば、そのデータを修正するため)。

これを行うには、新しいメニュー項目を定義する静的なメソッドに MenuCommand 引数を加えます。

Code snippet

[MenuItem("CONTEXT/RigidBody/New Option")]
private static void NewMenuOption(MenuCommand menuCommand)
{
    // コンテキストフィールドを使ってメニューコマンドから RigidBody コンポーネントを抜き出すことができます
    var rigid = menuCommand.context as RigidBody;
}

上の例のように、メニュー項目を起動するときに、そのコンテクストにあたるコンポーネントにコンテクストフィールドを使ってアクセスできます。

ContextMenu

この属性を使って、コンテキストメニューアイテムを定義できます。これは、 "CONTEXT/…" で始まるパスを持つ MenuItem 属性でメソッドを定義するのとまったく同じことを行います。

2 つの違いは、ContextMenu 属性を使う場合は、指定したコンポーネントのデフォルトコンテキストメニューを定義することで、一方、MenuItem アプローチの場合は、他のコンポーネントのメニュー (例えば、エンジンの一部のデフォルトコンポーネント) を「拡張」するということです。

例 – データをクリアするコンテキストメニューオプションを表示するコンポーネント

Code snippet

public class NameBehaviour :MonoBehaviour
{
    public string Name;
 
    [ContextMenu("Reset Name")]
    private static void ResetName()
    {
        Name = string.Empty;
    }
}

ContextMenuItem

この属性をコンポーネント (MonoBehaviour) クラスのフィールドに追加すると、より高い解像度でコンテキストメニューを追加することができます。上に表示された ContextMenu 属性が、コンポーネントレベルでコンテキストメニューを追加する一方、ContextMenuItem 属性でフィールドを作ると、独立したパブリックのフィールドに右クリックメニューを加えます。

この属性はメソッドでなくフィールドに加えられるため、2 つの引数を取ります。メニュー項目の表示名とそのメニューが選ばれると実行されるメソッド (インスタンスメソッド) の名前です。

例 – メソッドを追加し、コンポーネントのフィールドをある状態にランダムに初期化します。

Code snippet

public class NameBehaviour :MonoBehaviour
{
    [ContextMenuItem("Randomize Name", "Randomize")]
    public string Name;
 
    private void Randomize()
    {
        Name = "Some Random Name";
    }
}

このコードによって、コンポーネントの Name フィールドを右クリックすると、コンテキストメニューが表示されます。

Alt MenuItems 09

まとめ

この記事で説明したように、カスタムメニューを使って Unity エディターを拡張するのはとても容易です。

どのような規模のチームであっても、よく使う機能を追加しエディターから使用できるようにすることは推奨され、それにより、膨大な時間を節約することができます。

Lior Tal

コミュニティー作者

A software engineer, game developer, gamer and geek, trying to be active in the Unity community and to share my knowledge, as well as learn from others. For the past few years I've been busy doing software dev and game development for mobile platforms. I am interested in all topics related to software engineering and game dev, including: tools, methodologies, automated testing and game engines. On my website, i blog about my experiences in game development and software engineering (which are mostly related to Unity).

関連ドキュメント