Unity Editor Extensions – Menu Items

확인 완료한 버전: 4.5

-

난이도: 중급

The Unity editor allows adding custom menus that look and behave like the built-in menus. This can be very useful for adding commonly used functionality that is frequently needed to be accessible directly from the editor UI. In this lesson I’ll show how new menu items in the Unity editor are created and try to provide real-world example usages to every described topic.

Adding Menu Items

In order to add a new menu to the top-level toolbar, you should create an editor script (a script file that is placed anywhere in the project under a folder named Editor). Menu items are created in script code as static methods that are marked with the MenuItem attribute.

For example, it’s common to add a new “Tools” menu (or a top-level menu with your company’s name) to provide options that are commonly used by your team/company.

Here’s an example of adding a new Tools menu with an option under it (clears all PlayerPrefs data):

Code snippet

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

This creates a new editor menu called Tools, and places a menu item called Clear PlayerPrefs under it:

Alt MenuItems 01

It’s also possible to create new menu items under an existing menu (e.g: under the Window menu), and also to create multiple levels of menus for better structuring and organization (recommended):

Code snippet

using UnityEngine;
using UnityEditor;
 
public class MenuItemsExample
{
    // Add a new menu item under an existing menu
 
    [MenuItem("Window/New Option")]
    private static void NewMenuOption()
    {
    }
 
    // Add a menu item with multiple levels of nesting
 
    [MenuItem("Tools/SubMenu/Option")]
    private static void NewNestedOption()
    {
    }
}

This results in the following menu items:

Alt MenuItems 01

Hotkeys

To allow power users and keyboard junkies to work faster, new menu items can be assigned with hotkeys – shortcut key combinations that will automatically launch them.

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”).

Hotkey character combinations are added to the end of the menu item path, preceded by a space), as shown in the following examples:

Code snippet

// Add a new menu item with hotkey CTRL-SHIFT-A
 
[MenuItem("Tools/New Option %#a")]
private static void NewMenuOption()
{
}
 
// Add a new menu item with hotkey CTRL-G
 
[MenuItem("Tools/Item %g")]
private static void NewNestedOption()
{
}
 
// Add a new menu item with hotkey G
[MenuItem("Tools/Item2 _g")]
private static void NewOptionWithHotkey()
{
}

Menu items with hotkeys will display the key-combination that is used to launch them. For example, the code above results in this menu:

Alt MenuItems 03

Note: There’s no validation for overlapping hotkeys ! defining multiple menu items with the same hotkey results in only 1 option being called by hitting the key combination.

Special Paths

As seen, the path passed to the MenuItem attribute controls under which top level menu the new item will be placed.

Unity has a few “special” paths that act as context menus (menus that are accessible using right-click):

  • Assets – items will be available under the “Assets” menu, as well using right-click inside the project view.

  • Assets/Create – items will be listed when clicking on the “Create” button in the project view (useful when adding new types that can be added to the project)

  • CONTEXT/ComponentName – items will be available by right-clicking inside the inspector of the given component.

Here are some examples of how to use these special paths:

Code snippet

// Add a new menu item that is accessed by right-clicking on an asset in the project view
 
[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
}
 
// Add a new menu item that is accessed by right-clicking inside the RigidBody component
 
[MenuItem("CONTEXT/Rigidbody/New Option")]
private static void NewOpenForRigidBody()
{
}

The results for this code segment is these new menu options:

Alt MenuItems 04 Assets (project view) right-click menu

Alt MenuItems 05 New option available from the Asset’s CREATE button

Alt MenuItems 06 New context menu option for the RigidBody component

Validation

Some menu items only make sense in a given context, and should not be available otherwise. Enabling/disabling menu items according to their usage context is done by adding validation methods.

Validation methods are static methods, marked with the MenuItem attribute, passing true to the validation argument.

The validation method should have the same menu path as the menu it is validating, and should return a boolean value to determine whether the menu item is active or not.

For example, Validation methods can be used to add a right-click menu to Texture assets only under the project view:

Code snippet

[MenuItem("Assets/ProcessTexture")]
private static void DoSomethingWithTexture()
{
}
 
// Note that we pass the same path, and also pass "true" to the second argument.
[MenuItem("Assets/ProcessTexture", true)]
private static bool NewMenuOptionValidation()
{
    // This returns true when the selected object is a Texture2D (the menu item will be disabled otherwise).
    return Selection.activeObject.GetType() == typeof(Texture2D);
}

When right-clicking on anything that is not a texture in the project view, the menu item option will be disabled (greyed out):

Alt MenuItems 07

Controlling Order with Priority

Priority is a number that can be assigned to a menu item (passed to the MenuItem attribute) that controls the ordering of menu items under the root menu.

Menu items are also automatically grouped according to their assigned priority in increments of 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()
{
}

The code example results in the menu that has 2 groups of items, according to the assigned priority:

Alt MenuItems 08

If it is required to add and organize menu items under existing Unity menus, a bit of “guess work” is needed, as most of the built-in menu items use priorities. Another option is to use a tool such as Reflector and look at the source code for internal Unity code (such as UnityEditor.CreateBuildInWindows) that is responsible for creating some of the menus in the editor.

Related Classes

Below is a listing of a few extra classes that are related to adding new menu items.

MenuCommand

When adding a new menu item to an inspector (using “CONTEXT/Component”, as described above), sometimes it is necessary to get a reference to the actual component (e.g: to modify its data).

This can be done by adding a MenuCommand argument to the static method that defines the new menu item:

Code snippet

[MenuItem("CONTEXT/RigidBody/New Option")]
private static void NewMenuOption(MenuCommand menuCommand)
{
    // The RigidBody component can be extracted from the menu command using the context field.
    var rigid = menuCommand.context as RigidBody;
}

As seen in the code example, when invoking the menu item, the component that serves as its context can be accessed using the context field.

ContextMenu

This attribute allows defining context menu items. This works exactly the same as defining a method with the MenuItem attribute with a path that starts with “CONTEXT/…”.

The difference is that with this attribute, you define the default context menu for a given component, whereas with the MenuItem approach, you “extend” other components’ menus (for example – the default components that are part of the engine).

Example – a component that exposes a context menu option to clear its data:

Code snippet

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

ContextMenuItem

This attribute is added to fields of a component (MonoBehaviour) class, to allow adding context menus at a finer resolution. While the ContextMenu attribute shown above adds context menus at the component level, marking fields with this attribute will add a right-click menu to individual public fields.

Since this attribute is added to a field and not a method, it accepts 2 arguments: the display name of the menu item and a name of a method (instance method) to be invoked when the menu item is selected.

Example – Adding a method to randomly initialize a component’s field to some state:

Code snippet

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

This code results in this context menu when right-clicking on the Name field of this component:

Alt MenuItems 09

Wrap Up

As shown in this article, extending the Unity editor with custom menus can be pretty straightforward.

Building commonly used functionality and having it available from the editor is recommended for teams of all sizes and can be a huge time saver.

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).

관련 문서

Scripting

  1. Scripts as Behaviour Components
  2. Variables and Functions
  3. Conventions and Syntax
  4. C# vs JS syntax
  5. IF Statements
  6. Loops
  7. Scope and Access Modifiers
  8. Awake and Start
  9. Update and FixedUpdate
  10. Vector Maths
  11. Enabling and Disabling Components
  12. Activating GameObjects
  13. Translate and Rotate
  14. Look At
  15. Linear Interpolation
  16. Destroy
  17. GetButton and GetKey
  18. GetAxis
  19. OnMouseDown
  20. GetComponent
  21. Delta Time
  22. Data Types
  23. Classes
  24. Instantiate
  25. Arrays
  26. Invoke
  27. Enumerations
  28. Switch Statements
  1. Properties
  2. Ternary Operator
  3. Statics
  4. Method Overloading
  5. Generics
  6. Inheritance
  7. Polymorphism
  8. Member Hiding
  9. Overriding
  10. Interfaces
  11. Extension Methods
  12. Namespaces
  13. Lists and Dictionaries
  14. Coroutines
  15. Quaternions
  16. Delegates
  17. Attributes
  18. Events
  1. Introduction to ECS
  2. Introduction to the Entity Component System and C# Job System
  3. ECS Overview
  4. Implementing Job System
  5. Implementing ECS
  6. Using the Burst Compiler
  1. Building a Custom Inspector
  2. The DrawDefaultInspector Function
  3. Adding Buttons to a Custom Inspector
  4. Unity Editor Extensions – Menu Items
  5. An Introduction to Editor Scripting
  6. Creating a Spline Tool
  1. Simple Clock
  2. MonoDevelop's Debugger
  3. Unity Editor Extensions – Menu Items
  4. Creating Meshes
  1. AssetBundles and the AssetBundle Manager
  2. Mastering Unity Project Folder Structure - Version Control Systems
  1. Installing Tools for Unity Development
  2. Building your first Unity Game with Visual Studio
  3. Editing Unity games in Visual Studio
  4. Debugging Unity games in Visual Studio
  5. Graphics debugging Unity games in Visual Studio
  6. Taking Unity games to Universal Windows Platform
  7. Testing Unity games on Android in Visual Studio
  1. Scripting Primer and Q&A
  2. Scripting Primer and Q&A - Continued
  3. Scripting Primer and Q&A - Continued (Again)
  4. Persistence - Saving and Loading Data
  5. Object Pooling
  6. Introduction to Scriptable Objects
  7. How to communicate between Scripts and GameObjects
  8. Coding in Unity for the Absolute Beginner
  9. Sound Effects & Scripting
  10. Editor Scripting Intro
  11. Writing Plugins
  12. Property Drawers & Custom Inspectors
  13. Events: Creating a simple messaging system
  14. Ability System with Scriptable Objects
  15. Character Select System with Scriptable Objects
  16. Creating Basic Editor Tools
  1. Intro and Setup
  2. Data Classes
  3. Menu Screen
  4. Game UI
  5. Answer Button
  6. Displaying Questions
  7. Click To Answer
  8. Ending The Game and Q&A
  1. Intro To Part Two
  2. High Score with PlayerPrefs
  3. Serialization and Game Data
  4. Loading Game Data via JSON
  5. Loading and Saving via Editor Script
  6. Game Data Editor GUI
  7. Question and Answer
  1. Overview and Goals
  2. Localization Data
  3. Dictionary, JSON and Streaming Assets
  4. Localization Manager
  5. Startup Manager
  6. Localized Text Component
  7. Localized Text Editor Script
  8. Localization Q&A
  1. Introduction and Session Goals
  2. Particle Launcher
  3. Particle Collisions
  4. ParticleLauncher Script
  5. Particle Collisions and Scripting
  6. Random Particle Colors
  7. Drawing Decals with Particles
  8. Collecting Particle Information For Display
  9. Displaying Particles Via Script
  10. Droplet Decals
  11. Questions and Answers
  1. Introduction and Goals
  2. Project Architecture Overview
  3. Creating Rooms
  4. Creating Exits
  5. Text Input
  6. Reacting To String Input
  7. Input Actions And The Delegate Pattern
  8. Questions and Answers
  1. Introduction and Goals
  2. Project Architecture and Review
  3. Displaying Item Descriptions
  4. Examining Items
  5. Taking Items
  6. Displaying Inventory
  7. Action Responses
  8. Preparing The Use Item Dictionary
  9. Creating The Use Action
  10. Questions and Answers