转载-Unity3d编辑器扩展

添加菜单项

为了要在顶层工具栏中创建一个新的菜单项,你必须去创建一个编辑器脚本(在项目Editor目录下的一个脚本)。此菜单项需要是一个静态的方法且必须使用MenuItem属性来标识。例如,去添加一个你的团队和公司经常使用的命令到“Tools”菜单。 
下面的示例,在Tools菜单下添加了一个“Clear PlayerPrefs”选项:

using UnityEngine;
using UnityEditor;

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

这段代码创建了一个叫“Tools”的菜单,并在下面放置了一个叫“Clear PlayerPrefs”的菜单项。 
这里写图片描述 
当然我们也可以在一个现成的菜单项下面创建新的菜单项(例如:在“Windows”菜单下),也可以创建多级子菜单便于更好的组织菜单项目:

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()
    {
    }
}

上面的代码产生的结果如下: 
这里写图片描述

快捷键

为了使超级用户和喜欢使用键盘的用户工作的更快捷,我们可以为新的菜单项关联一个快捷键-使用快捷键的组合将自动的启动他们菜单项。 
下面是被指定的键(它们也可以组合起来使用):

  • %-CTRL 在Windows / CMD在OSX
  • # -Shift
  • & -Alt
  • LEFT/RIGHT/UP/DOWN-光标键
  • F1…F12
  • HOME,END,PGUP,PDDN

字母键不是key-sequence的一部分,要让字母键被添加到key-sequence中必须在前面加上下划线(例如:_g对应于快捷键”G”)。 
快捷键的组合被添加在菜单项的路径后面,并以一个空格分隔。如下显示的示例:

// 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()
{
}

使用了快捷键的菜单项将显示用于启动它们的快捷键,示例如下: 
这里写图片描述 
注意:这里没有验证重复的快捷键,如果定义了多个相同的快捷键,那么也只有一个菜单项被调用。

特殊路径

显示,传递到MenuItem属性上的路径确定了新的菜单项将被放置在哪个顶层菜单下。Unity有些特殊的路径作用于上下文菜单(通过右键访问的菜单):

  • Assets -菜单项将被显示在“Assets”菜单下,同时也显示在右键单击项目视图时弹出的菜单中。
  • Asset/Create - 菜单项将被列出在,当你在项目视图中单了右键菜单里的“Create”子菜单中(当你创建了能够添加项目的新类型时,此功能是是非常有用的)。
  • CONTEXT/ComponentName - 菜单项将出现在给定组件的上下文菜单(右键单击显示的菜单)中。

下面显示了一些如何使用特殊路径的示例:

// 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()
{
}

上面代码片段产生的结果如下图:

这里写图片描述

这里写图片描述

这里写图片描述

有效性验证

有些菜单项仅在指定的情况下才可用,否则就应该被禁用。根据它的上下文添加一个验证方法来启用/禁用一个菜单项。 
验证方法是一个静态的,并使用MenuItem属性标记的一个方法,且此属性传递true作为一个验证参数。 
这个验证方法应该和菜单的命令方法有相同的路径,并且要有一个boolean的返回值,用以确认菜单是否被激活或者禁用。 
例如,验证方法能够被用于在项目视图里一个纹理上的右键菜单:

[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);
}

当在非任意纹理上单击右键时,此菜单项将会被显示成灰色: 
这里写图片描述

控制菜单的优先顺序

优先级是个被赋值到菜单项一个数字(传递给MenuItemde的第3个参数),它控制了菜单的显示顺序。 
菜单项也能够自动的分组,每50个一个组:

[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()
{
}

上面的代码示例显示如下的结构,菜单项被分为了两个组:

这里写图片描述

其他相关的类

下面列出了对于添加菜单项一些相关的类。

MenuCommand

当添加一个新的菜单项到Inspector中(使用 “CONTEXT/Component”),有时候获取一个真实组件的引用也是有必要的(例如:修改它的数据)。 
这可以通过给新菜单项的静态方法添加一个MenuCommand参数。

[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;
}

ContextMenu

这个属性允许你去定义上下文菜单。它和使用MenuItem并以“CONTEXT/…”作为路径定义菜单项一样。 
这个属性不同的是,你能给指定的组件定义默认的上下文菜单项,然而使用MeneItem只是为了扩展现有的组件菜单,比如引擎默认的组件。 
示例-组件将显示一个用于清除数据的菜单项:

public class NameBehaviour : MonoBehaviour
{
    public string Name;

    [ContextMenu("Reset Name")]
    private static void ResetName()
    {
        Name = string.Empty;
    }
}

ContextMenuItem

这个属性被添加到组件类的字段上,上面显示了ContextMenu属性在组件上下文菜单中添加了一个菜单项,然后ContextMenuItem属性将在字段的上下文菜单中添加一个菜单项。 
由于这个属性被添加到了一个字段上没有方法,所有它接受两个参数:一个用于显示菜单项的名字,一个用于指定一个当菜单被选中时要调用的实例方法。 
实例-添加一个随机初始化字段的方法:

public class NameBehaviour : MonoBehaviour
{
    [ContextMenuItem("Randomize Name", "Randomize")]
    public string Name;

    private void Randomize()
    {
        Name = "Some Random Name";
    }
}

上面代码的结果显示了当在字段上单击右键时弹出的菜单项:

这里写图片描述

AddComponentMenu

此属性允许你去放置脚本到“Component”菜单下的任意位置,而不只是在“Component->Scripts”菜单下。你能使用它去更好的组织你的脚本。这个属性能够改善添加脚本的工作流程。重要提示:你需要重启才生效。

using UnityEngine;

[AddComponentMenu("Transform/Follow Transform")]
public class FollowTransform : MonoBehaviour
{
}

GenericMenu

GenericMenu让你可以创建一个自定义的上下文菜单和下拉菜单,下面这个示例打开一个带有绿色区域的窗口,在绿色区域上单击右键将显示一个菜单,当触发了菜单中选中的项时将触发一个回调。

using UnityEngine;
using UnityEditor;
using System.Collections;

// This example shows how to create a context menu inside a custom EditorWindow.
// context-click the green area to show the menu

public class GenericMenuExample : EditorWindow
{

    [MenuItem("Example/Open Window")]
    static void Init()
    {
        var window = GetWindow<GenericMenuExample>();
        window.position = new Rect(50, 50, 250, 60);
        window.Show();
    }

    void Callback(object obj)
    {
        Debug.Log("Selected: " + obj);
    }

    void OnGUI()
    {
        Event currentEvent = Event.current;
        Rect contextRect = new Rect(10, 10, 100, 100);
        EditorGUI.DrawRect(contextRect, Color.green);

        if (currentEvent.type == EventType.ContextClick)
        {
            Vector2 mousePos = currentEvent.mousePosition;
            if (contextRect.Contains(mousePos))
            {
                // Now create the menu, add items and show it
                GenericMenu menu = new GenericMenu();
                menu.AddItem(new GUIContent("MenuItem1"), false, Callback, "item 1");
                menu.AddItem(new GUIContent("MenuItem2"), false, Callback, "item 2");
                menu.AddSeparator("");
                menu.AddItem(new GUIContent("SubMenu/MenuItem3"), false, Callback, "item 3");
                menu.ShowAsContext();
                currentEvent.Use();
            }
        }
    }
}

总结

这篇文章说展示的,在Unity编辑器中去扩展一个菜单项是非常简单的。 
在编辑器中为常用功能建立菜单项。可以为规范团队开发并且能够节约很多时间。

猜你喜欢

转载自my.oschina.net/u/3184885/blog/912616