Unity编辑器扩展(一)编辑器扩展基础

一、MenuItem

MenuItem可以向主菜单和Inspector面板上下文菜单中添加菜单项。
它具有如下三个参数:

  • itemName:菜单路径
  • isValidateFunction:是否为校验函数
  • priority:优先级

itemName这个参数是必传的,它用于指定菜单的路径。注意使用「MenuItem」特性的方法都必须是静态方法。

[MenuItem("AdvancedEditor/01-MenuItem/Test")]  
private static void Test()  
{
    
      
    Debug.Log("Test");  
}

效果如下

我们可以在路径的结尾以类似于%_q的形式定义菜单的快捷键

[MenuItem("AdvancedEditor/01-MenuItem/Test %_q")]  
private static void Test()  
{
    
      
    Debug.Log("Test");  
}

效果如下

常见的符号代表的快捷键如下

符号 按键
% Ctrl/Command
# Shift
& Alt
_a、_b、…_z A~Z
LEFT、RIGHT、UP、DOWN 方向键
F1、F2…F12 F1~F12

在路径的开头添加CONTEXT,表示这是Inspector面板上下文菜单中的菜单项。如果方法参数为MenuCommand,则会传入当前组件

[MenuItem("CONTEXT/Rigidbody/Init")]  
private static void RigidbodyInit(MenuCommand cmd)  
{
    
      
    var rigidbody = cmd.context as Rigidbody;  
    if (rigidbody != null)   
		Debug.Log(rigidbody.name);  
}

效果如下

isValidateFunction参数标记了当前函数是否是校验函数。比如下面这个例子,DeleteValid()被标记为了校验函数,那么与其菜单路径相同的非校验函数DeleteSelectedItem(),就只有在DeleteValid()返回true时才能点击。

/// <summary>
/// 添加菜单栏按钮
/// </summary>
[MenuItem("AdvancedEditor/01-MenuItem/Delete Selected Item %_d",false,1)]
private static void DeleteSelectedItem()
{
    
    
	Debug.Log("DeleteSelectedItem");
	foreach (var obj in Selection.objects)
	{
    
    
		// 记录删除操作,允许撤销
		Undo.DestroyObjectImmediate(obj);
	}
}
/// <summary>
/// 校验方法
/// </summary>
[MenuItem("AdvancedEditor/01-MenuItem/Delete Selected Item %_d",true,1)]
private static bool DeleteValid()
{
    
    
	if (Selection.objects.Length > 0)
		return true;
	return false;
}

效果如下

最后一个参数priority,顾名思义就是决定了菜单项在菜单中的位置。如果没有显式指定的话,默认值为1000。另外,如果想让菜单项之间出现上图中的横线,需要相邻两个菜单项的priority相差10以上。

二、ContextMenu和ContextMenuItem

ContextMenu用来给组件的右键菜单增加菜单选项
ContextMenuItem用来给属性的右键菜单增加菜单选项
这两个特性属于UnityEngine命名空间下,一般在继承了MonoBehaviour类中使用,用来给自定义组件添加右键菜单选项。

ContextMenu的用法如下

/// <summary>  
/// 给组件添加右键菜单  
/// </summary>  
[ContextMenu("Do Something")]  
private void DoSomething()  
{
    
      
    Debug.Log("Do Something");  
}

效果如下

ContextMenuItem的用法如下

/// <summary>  
/// 给属性添加右键菜单  
/// </summary>  
[ContextMenuItem("Health","HealthDescription")]  
public float Health;  
  
private void HealthDescription()  
{
    
      
    Debug.Log("生命值");  
}

效果如下:

三、自定义对话框

自定义对话框实现起来非常简单,只需要让我们写的脚本继承ScriptableWizard类,然后通过调用DisplayWizard()方法即可将对话框展示出来。脚本中的字段会显示在对话框中。下面我们来实现一个简单的自定义对话框

public class CustomWizard : ScriptableWizard
{
    
    
	[MenuItem("AdvancedEditor/02-CustomWizard/CustomWizard", false, 2)]
	private static void ShowCustomWizard()
	{
    
    
		DisplayWizard<CustomWizard>("自定义对话框");
	}

	public float Health = 10f;
	public float Speed = 20f;
}

效果如下

可以看到生成的对话框的右下角是有一个按钮的。这个按钮当然也可以自定义名称和点击事件。按钮的名称可以在DisplayWizard()方法的第二个参数中传入,点击事件可以通过实现OnWizardCreate()事件函数传入

[MenuItem("AdvancedEditor/02-CustomWizard/CustomWizard", false, 2)]
private static void ShowCustomWizard()
{
    
    
	DisplayWizard<CustomWizard>("自定义对话框","这是一个按钮");
}

private void OnWizardCreate()
{
    
    
	Debug.Log("点击了按钮");
}

效果如下

我们还可以再添加一个按钮(最多两个按钮)。只需要在DisplayWizard()方法的第三个参数中传入按钮名称,并实现OnWizardOtherButton()事件函数即可

[MenuItem("AdvancedEditor/02-CustomWizard/CustomWizard", false, 2)]
private static void ShowCustomWizard()
{
    
    
	DisplayWizard<CustomWizard>("自定义对话框","这是一个按钮","这是另一个按钮");
}

private void OnWizardOtherButton()
{
    
    
	Debug.Log("点击了另一个按钮");
}

效果如下

ScriptableWizard内置的两个成员helpStringerrorString可以在对话框中展示提示信息和错误信息,用法如下

// 对话框开启、字段变更时调用
private void OnWizardUpdate()
{
    
    
	helpString = "";
	errorString = "";
	if (Selection.gameObjects.Length == 0)
	{
    
    
		errorString = "您未选择物体";
	}
	else
	{
    
    
		helpString = $"您选择了{
      
      Selection.gameObjects.Length}个物体";
	}
}
// 选中的元素发生变更时调用
private void OnSelectionChange()
{
    
    
	OnWizardUpdate();
}

效果如下

也可以使用EditorWindow类下的ShowNotification()方法显示提示信息

private void OnWizardOtherButton()
{
    
    
	ShowNotification(new GUIContent("点击了另一个按钮"));
}

效果如下

最后,如果我们想创建类似于「Inspector」面板这种系统内置的窗口,可以让脚本继承EditorWindow类来实现,然后通过OnGUI绘制其中的元素。

public class CustomEditorWindow : EditorWindow
{
    
    
	[MenuItem("AdvancedEditor/02-CustomWizard/CustomEditorWindow", false, 3)]
	private static void ShowWindow()
	{
    
    
		var window = GetWindow<CustomEditorWindow>();
		window.Show();
	}

	private string _name = "";
	private void OnGUI()
	{
    
    
		GUILayout.Label("名称");
		_name = GUILayout.TextField(_name);
		if (GUILayout.Button("创建物体"))
		{
    
    
			GameObject go = new GameObject(_name);
			Undo.RegisterCreatedObjectUndo(go,"Create GameObject");
		}
	}
}

效果如下

猜你喜欢

转载自blog.csdn.net/LWR_Shadow/article/details/127135981