作者最新更新

游戏开发工具

UnityEditor之MenuItem属性

720

95 次收藏2024-08-31 21:52:40发布

MenuItem 属性用于向主菜单和检视面板上下文菜单添加菜单项。

该 MenuItem 属性能够将任何静态函数转变为菜单命令,仅静态函数可使用 MenuItem 属性

1、要创建热键

您可以使用以下特殊字符:%(在 Windows 上为 ctrl,在 macOS 上为 cmd)、# (shift)、& (alt)。如果不需要特殊的修改键组合,该键可以在下划线后给出。例如,要创建一个带有热键 shift-alt-g 的菜单,可以使用“MyMenu/Do Something #&g”。要创建带有热键 g 而不按下修改键的菜单,则使用“MyMenu/Do Something _g”。

2、一些特殊的键盘键可支持作为热键

例如,“#LEFT”可映射到 shift-left。支持这一功能的键为:LEFT、RIGHT、UP、DOWN、F1 .. F12、HOME、END、PGUP 和 PGDN。

热键文本前必须有一个空格字符(“MyMenu/Do_g”不能被解释为热键,而“MyMenu/Do _g”则可以被解释为热键)。

3、子菜单结构

将菜单项添加到“GameObject/”菜单,以在创建自定义游戏对象时,确保调用 GameObjectUtility.SetParentAndAlign,从而确保在发生上下文单击事件时, 对新的游戏对象进行正确地重定父级(请参阅以下示例)。您的函数也应该调用 Undo.RegisterCreatedObjectUndo,以使创建操作可撤销并将 Selection.activeObject 设置到新创建的对象上。另请注意,为了将“GameObject/”中的菜单项 传播到层级视图 Create 下拉菜单和层级视图上下文菜单,它必须与 其他游戏对象创建菜单项归为一组。

4、菜单优先级

这可以通过将其优先级 设为 10 来实现(请参阅以下示例)。请注意,对于“GameObject/Create Other” 中没有明确优先级设置且支持旧版项目的 MenuItem 来说,接收到的优先级为 10 而非默认的 1000, 我们建议使用比“Create Other”更具描述性的类别名称,并将优先级 显式设置为 10。


一、MenuItem 属性

1、itemName:菜单名称路径

特殊路径:

CONTEXT: 为组件添加菜单项

Assets: 对应顶部菜单 Assets,并添加 Project 面板右键菜单

GameObject: 对应顶部菜单 GameObject,priority 值在 149 时,添加 Hierarchy 面板右键菜单

Component: 对应顶部菜单 Component,对应 Inspector 面板的 Add Component 窗口。但是不知道怎么用,用 AddComponentMenu吧。

2、isValidateFunction:不写为 false,true 则点击菜单前就会调用

3、priority:菜单项显示排序 默认 1000

二、创建多级菜单
[MenuItem("一级菜单/二级菜单上/三级菜单")]
static void MenuOne()
{
  //功能
}

[MenuItem("一级菜单/二级菜单下")]
static void MenuTwo()
{
  //功能
}

1.jpg

三、创建带快捷键的菜单

在 MenuItem 的双引号菜单路径最后 + 空格 + 快捷键字符

快捷键可任意组合使用

英文字母 :_字母 (不区分大小写)

常用快捷键:

符号字符
%Ctr/Command
#Shift
&Alt
LEFT/Right/UP/DOWN方向键
F1-F2F 功能键
_g字母 g

4.jpg

四、创建可被勾选的菜单
//设置勾选状态
//Menu.SetChecked(string menuPath, bool isChecked)
//获取勾选状态
//Menu.GetChecked(string menuPath)

[MenuItem("一级菜单/二级菜单上 #_A")]
static void MenuA()
{
 string menuPath = "一级菜单/二级菜单上 #_A";
 bool isChecked = !Menu.GetChecked(menuPath);
 Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单中 %#_B")]
static void MenuB()
{
 string menuPath = "一级菜单/二级菜单中 %#_B";
 bool isChecked = !Menu.GetChecked(menuPath);
 Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单下 %&_C")]
static void MenuC()
{
 string menuPath = "一级菜单/二级菜单下 %&_C";
 bool isChecked = !Menu.GetChecked(menuPath);
 Menu.SetChecked(menuPath, isChecked);
}

五、检查菜单是否使用

通过函数判断菜单是否可使用,操作如下所示:

[MenuItem("菜单路径名")]
static void 方法() { }

[MenuItem("菜单路径名"),true]
static void 验证方法()
{
  return bool值; //返回true 改菜单启用
}

具体实现操作用例:

[MenuItem("一级菜单/二级菜单上")]
static void MenuA()
{
   string menuPath = "一级菜单/二级菜单上";
   bool isChecked = !Menu.GetChecked(menuPath);
   Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单中")]
static void MenuB()
{
   string menuPath = "一级菜单/二级菜单中";
   bool isChecked = !Menu.GetChecked(menuPath);
   Menu.SetChecked(menuPath, isChecked);

   EditorPrefs.SetBool("MenuCValidate", isChecked);
}

[MenuItem("一级菜单/二级菜单下")]
static void MenuC()
{
   string menuPath = "一级菜单/二级菜单下";
   bool isChecked = !Menu.GetChecked(menuPath);
   Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单下", true)]
static bool MenuCValidate()
{
   bool flag = EditorPrefs.GetBool("MenuCValidate");
   Menu.SetChecked("一级菜单/二级菜单中", flag);
   return flag;
}

六、菜单排序

在 priority 小的位置在上方 不配置默认为 1000

当相邻两个菜单的 priority 值差距超过 10 时 就会分组 中间出现一条横线

多级菜单的 priority 按照子级里面最小的 priority 算

[MenuItem("一级菜单/二级菜单上", false, 3)]
static void MenuA()
{
	string menuPath = "一级菜单/二级菜单上";
	bool isChecked = !Menu.GetChecked(menuPath);
	Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单中", false, 2)]
static void MenuB()
{
	string menuPath = "一级菜单/二级菜单中";
	bool isChecked = !Menu.GetChecked(menuPath);
	Menu.SetChecked(menuPath, isChecked);
}

[MenuItem("一级菜单/二级菜单下", false, 1)]
static void MenuC()
{
	string menuPath = "一级菜单/二级菜单下";
	bool isChecked = !Menu.GetChecked(menuPath);
	Menu.SetChecked(menuPath, isChecked);
}

七、Hierarchy 右键菜单

Hierarchy 右键菜单是菜单栏的 GameObject 菜单栏下的菜单,并且 priority 在 149 范围内

[MenuItem("GameObject/二级菜单", false, 1)]
static void MenuA()
{

}

八、Project 右键菜单

Project 右键菜单是菜单栏的 Assets 菜单栏下的菜单

[MenuItem("Assets/二级菜单", false, 1)]
static void MenuA()
{

}

九、Inspector 组件右键菜单

组件右键菜单是使用特殊路径 CONTEXT 创建的

MenuCommand 可以获取到该组件

[MenuItem("CONTEXT/组件名/菜单名")]
static void 方法名(MenuCommand cmd)
{
	//组件名 t = cmd.context as 组件名;
	//对该组件进行操作
}

[MenuItem("CONTEXT/Transform/Reset功能")]
static void ClearTransformMenu(MenuCommand cmd)
{
	Transform t = cmd.context as Transform;
	t.position = Vector3.zero;
	t.rotation = Quaternion.identity;
	t.localScale = Vector3.zero;
	GameObject obj = new GameObject();
	obj.transform.parent = t.gameObject.transform;
}

十、AddComponentMenu 特性

AddComponentMenu 直接加载类上,会自动将菜单加到 Component 下,并加在 Inspector 面板的 AddComponentMenu 里。

AddComponentMenu(string menuName, int order)
menuName:菜单名路径
order:菜单项排序

使用用例:

[AddComponentMenu("自定义/Test", 1)]
public class Test : MonoBehaviour
{

}


十一、ContextMenu特性添加组件右键菜单

ContextMenu(string itemName, bool isValidateFunction, int priority)

itemName:菜单名称

isValidateFunction:不写为false,true则点击菜单前就会调用 

priority:菜单项显示排序 默认 1000000

使用用例:

[AddComponentMenu("自定义/Test", 1)]
public class Test : MonoBehaviour
{
    [ContextMenu("添加空物体")]
    public void AddGameObject()
    {
        transform.position = Vector3.zero;
        transform.rotation = Quaternion.identity;
        transform.localScale = Vector3.zero;
        GameObject obj = new GameObject();
        obj.transform.parent = transform;
    }
}