本专栏基础资源来自唐老狮和siki学院,仅作学习交流使用,不作任何商业用途,吃水不忘打井人,谨遵教诲
编辑器扩展内容实在是太多太多了(本篇就有五千字++)
所以分为两个篇章而且只用一些常用api举例,更多的还是起到留下学习印象的作用
就像引用类型的堆和栈一样,本文提供栈的作用,指向的内存堆为官方文档
什么是编辑器扩展
Unity编辑器扩展是指通过编写自定义脚本和插件,利用Unity提供的API来增强和扩展Unity编辑器的功能,这些扩展可以显著提高开发效率和灵活性
前置知识:GUI
可能需要熟悉的知识: EditorGUI - Unity 脚本 API
大部分的编辑器扩展脚本都需要写在Editor文件中,这样unity打包的时候,不会打包出去该文件
1.MenuItem类
作用:在unity未运行时 一键使用自定义静态函数
MenuItem - Unity 脚本 API --- MenuItem - Unity 脚本 API
1.创建菜单栏
[MenuItem("扩展菜单名/一级菜单名/方法名任意")] 菜单级数任意
实现效果如下
引入命名空间,函数必须为静态函数
cs
using UnityEngine;
cs
public class T1
{
//在unity不同的地方一键执行静态函数
[MenuItem("扩展菜单名/TestMethod/Function1")]
public static void Function1(){
Debug.Log("输出任意一句话");
}
}
可以添加特殊标识符,在不同的窗口创建使用,而不只是通过菜单栏中去选择
类似这样
总结一下规则如下图
2.绑定快捷键规则
3.在组件菜单中拓展自定义脚本
[AddComponentMenu("一级菜单/二级菜单/脚本名建议和实际脚本一致")] 菜单级数任意
众所周知 ,在unity中脚本就可以理解为组件
所以在菜单栏中的组件菜单中,是可以将自定义的脚本添加进去的
使用特性AddComponentMenu:
cs
//在组件菜单中添加 自定义脚本(组件)
[AddComponentMenu("一级菜单/二级菜单/脚本名")]
public class T2 : MonoBehaviour
{
}
选中物品就可以添加了
4.为脚本添加使用自定义函数
[MenuItem("CONTEXT/脚本名/一级菜单名/函数名任意")] 菜单级数任意
cs
//在组件菜单中添加 自定义脚本(组件)
[AddComponentMenu("一级菜单/二级菜单/脚本名")]
public class T2 : MonoBehaviour
{
[MenuItem("CONTEXT/T2/一级菜单名/Function1")]
public static void Function2() {
Debug.Log("输出任意一句话");
}
}
2.EditorWindow 类
继承了 EditorWindow类的编辑器脚本, 你可以在这个窗口中添加自定义方法,如下图演示将创建一个名为Name,有一个任意内容label的窗口
例如如下窗口
cs
public class Window : EditorWindow
{
[MenuItem("MyWindow/window1")]
private static void MyWindow()
{
Window w =EditorWindow.GetWindow<Window>("Name");
w.Show();
}
private void OnGUI() {
GUILayout.Label("任意内容");
}
}
3.EditorGUILayout类
在具体绘制这一点,unity提供了一个新的类叫做EditorGUILayout,功能与GUILayout相似加入了自动布局功能
举例:每种元素都用常用api
cs
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEditor;
using UnityEngine;
public class Window : EditorWindow
{
[MenuItem("MyWindow/window1")]
private static void MyWindow()
{
Window w =EditorWindow.GetWindow<Window>("Name");
w.Show();
}
//层级和标签
int layer;
string tag;
//选择枚举
enum E_AnyType{
a=1,
b=2,
c=4,
d=8,
//要将枚举中的变量定义为2的幂次方,原因是多选枚举时,是按照 或运算 将得出的结果记录下来
//比如a=1,二进制为0001,b=2,二进制为0010,或运算后结果为0011 = 3
//如果不按此规则,a=1,b=2,c=3,当a|b之后,得到的结果就变成了c,而不是多选a和b
}
E_AnyType single;
E_AnyType multiple;
//字符串选择对应数组值
int returnNum;
string[] options = { "op1", "op2", "op3", "op4" };
int[] result = { 1,2,3,4};
//关联资源
GameObject obj;
int value;//整形输入框
//折叠控件
bool isHide;
bool isGroupHide;
//滑动条
float slider;
int intSlider;
float min;
float max;
private void OnGUI() {
EditorGUILayout.LabelField("页签");
layer =EditorGUILayout.LayerField(layer);//return int
tag =EditorGUILayout.TagField("标签");//return sting
single = (E_AnyType)EditorGUILayout.EnumPopup("单选枚举",single);//return typeof(E_AnyType)
multiple = (E_AnyType)EditorGUILayout.EnumFlagsField("多选枚举",multiple);
returnNum = EditorGUILayout.IntPopup("字符串对应数组", returnNum, options, result);
EditorGUILayout.LabelField(returnNum.ToString());
EditorGUILayout.DropdownButton(new GUIContent("按钮"), FocusType.Passive);//return bool
isHide = EditorGUILayout.Foldout(isHide,"折叠控件 bool包裹内容");
if(isHide){
obj = EditorGUILayout.ObjectField("关联资源对象框", obj, typeof(GameObject), true) as GameObject;
value = EditorGUILayout.IntField("输入框", value);
}
isGroupHide = EditorGUILayout.BeginFoldoutHeaderGroup(isGroupHide,"折叠组控件 必须包括开始和结束");
EditorGUILayout.EndFoldoutHeaderGroup();
//开关和开关组类似于折叠控件 关键词:Toggle
slider =EditorGUILayout.Slider("滑动条",slider,0,1);
intSlider = EditorGUILayout.IntSlider("整型滑动条",intSlider,0,1);
//双块滑动条
EditorGUILayout.MinMaxSlider("双块",ref min,ref max,0,1);
EditorGUILayout.Space(10);//间隔框
//提示框
EditorGUILayout.HelpBox("提示框",MessageType.Warning);//MessageType选择类型
}
}
4.EditorGUIUtility类
该类是 EditorGUI 的各种辅助程序
cs
public class 资源加载和工具类 : EditorWindow
{
[MenuItem("资源加载部分/openWindow")]
private static void OpenWindow(){
资源加载和工具类 l = EditorWindow.GetWindow<资源加载和工具类>("资源加载与工具示例");
l.Show();
}
Texture texture;
private void OnGUI() {
//加载Editor Default Resources 文件夹下的资源 要求有后缀名
texture = EditorGUIUtility.Load("test.jpg") as Texture;//有判空方法 EditorGUIUtility.LoadRequired()
GUI.DrawTexture(new Rect(0,50,100,100),texture);//绘制
//搜索框和选择资源
if (EditorGUILayout.DropdownButton(new GUIContent("打开资源搜索框"), FocusType.Passive))
EditorGUIUtility.ShowObjectPicker<Texture>(null,true,"",0);//搜索
if(Event.current.commandName == "ObjectSelectorUpdated") {
texture = EditorGUIUtility.GetObjectPickerObject() as Texture;//获取
EditorGUIUtility.PingObject(texture);//高亮选中资源在Project中
Debug.Log(texture.name);
}
//窗口事件传递 当SendEvent(e)执行后 会发出一个ExecuteCommand枚举类型 只需要检测这个类型 并且事件名相同即可接收
if (EditorGUILayout.DropdownButton(new GUIContent("传递事件按钮"), FocusType.Passive))
{
Event e = EditorGUIUtility.CommandEvent("事件名");
SendEvent(e);
}
//接收事件窗口 可以写在其他窗口之中
if (Event.current.type == EventType.ExecuteCommand && Event.current.commandName == "事件名") {
Debug.Log("接收到了事件");
}
}
}
5.Selection类
用于访问编辑器中的选择对象,这个类过于简单了,就不做演示,可以自行查看文档或看下面唐老师的注释
cs
#region 知识点一 获取当前选择的Object
//获取当前在面板上选择的游戏物体Object
//未选择则返回Null
//选择多个则返回第一个选择的游戏物体
//Selection.activeObject
#endregion
#region 知识点二 获取当前选择的GameObject
//获取当前在面板上选择的游戏物体GameObject
//未选择则返回Null
//选择多个则返回第一个选择的游戏物体
//Selection.activeGameObject
#endregion
#region 知识点三 获取当前选择的Transform
//获取当前在面板上选择的游戏物体的Transform
//未选择则返回Null
//选择多个则返回第一个选择的游戏物体
//Selection.activeTransform
//只能获取到场景中的对象的Transform
#endregion
#region 知识点四 获取当前选择的所有Object
//获取当前在面板上选择的物体数组
//未选择则返回Null
//Selection.objects
#endregion
#region 知识点五 获取当前选择的所有GameObject
//获取当前在面板上选择的游戏物体或Project中预设体 GameObject数组
//未选择则返回Null
//Selection.gameObjects
//可以遍历获取所有信息
#endregion
#region 知识点六 获取当前选择的所有Transform
//获取当前在面板上选择的游戏物体Transform数组
//未选择则返回Null
//Selection.transforms
//可以遍历获取所有信息
#endregion
}
6.Event类
作用:检测Unity中的事件/输入,或者是 用于UnityGUI 布局/渲染事件
你如果将此类写在OnGUI之中并配合EditorWindow的话那么其所有的方法与属性都将与自定义窗口有关
由于api过多且简单,故不做全部演示
cs
private void OnGUI() {
//有一个大类 Event.current
Vector2 mousePostion = Event.current.mousePosition;
Debug.Log(mousePostion);
}