Unity编辑器扩展快速回顾

知识点来源:总结人间自有韬哥在, 唐老狮,豆包

目录

  • 1.自定义菜单栏拓展
    • 1.1.Editor文件夹用途
    • 1.2.添加自定义页签
    • 1.3.Component菜单加脚本
    • 1.4.Inspector脚本右键菜单
    • 1.5.快捷键设置
  • 2.自定义窗口扩展
    • 2.1.创建窗口类
    • 2.2显示窗口
    • 2.3.窗口事件回调函数
    • 2.4.窗口中常用的生命周期函数
    • 2.5.编辑器窗口类中的常用成员
  • 3.EditorGUI
    • 3.1. EditorWindow 类成员
    • 3.2. EditorGUILayout 相关功能
  • 4.EditorGUIUtility
    • 4.1 资源加载
    • 4.2 搜索框查询对象选中提示
    • 4.3 窗口事件传递坐标转换
    • 4.4 指定区域使用对应鼠标指针
    • 4.5 绘制色板绘制曲线
  • 5.Selection
  • 6.Event
  • 7.Inspector窗口拓展
    • 7.1.方法和参数
    • 7.2.重写
    • 7.3.接口
  • 8.Handles
    • 8.1.方法
    • 8.2. 静态参数
  • 9.Gizmos
    • 9.1.方法
    • 9.2. 静态参数
    • 9.3. 响应函数
  • 10.EditorUtility
  • 11.AssetDatabase
  • 12.PrefabUtility
  • 13.EditorApplication
  • 14.CompilationPipeline
  • 15.AssetImporter和AssetPostprocessor
    • 15.1.AssetPostprocessor
    • 15.2.AssetImporter

1.自定义菜单栏拓展

1.1.Editor文件夹用途

Unity中,Editor为特殊文件夹,使用UnityEditor命名空间的脚本需放此,避免打包报错。

1.2.添加自定义页签

菜单栏

  • 命名空间:UnityEditor
  • 特性:MenuItem
  • 用法:[MenuItem("页签/选项")] 修饰静态函数
  • 例:[MenuItem("教程/TestFun")] static void TestFun() { Debug.Log("TestFun"); }

Hierarchy窗口

  • 用法:[MenuItem("GameObject/页签/选项")]
  • 例:[MenuItem("GameObject/教程/TestFun2")] static void TestFun2() { Debug.Log("TestFun2"); }

Project窗口

  • 用法:[MenuItem("Assets/页签/选项")]
  • 例:[MenuItem("Assets/教程/TestFun3")] static void TestFun3() { Debug.Log("TestFun3"); }

1.3.Component菜单加脚本

  • 命名空间:UnityEngine
  • 特性:AddComponentMenu
  • 用法:[AddComponentMenu("选项")] 修饰继承MonoBehaviour的脚本
  • 例:[AddComponentMenu("教程/Lesson02")] public class Lesson02 : MonoBehaviour {}

1.4.Inspector脚本右键菜单

  • 用法:[MenuItem("CONTEXT/脚本名/页签/选项")]
  • 例:[MenuItem("CONTEXT/Lesson02/教程/TestFun4")] static void TestFun4() { Debug.Log("TestFun4"); }

1.5.快捷键设置

单键:路径后加 “ _ 按键”;组合键:用 %(ctrl)、#(shift)、&(alt)

  • 例:[MenuItem("教程/TestFun5 _F4")] static void TestFun5() { Debug.Log("TestFun5"); }

2.自定义窗口扩展

2.1.创建窗口类

UnityEditor 命名空间下,我们通过创建一个继承自 EditorWindow 的类来实现自定义窗口。例如:

using UnityEditor;

public class Lesson03_自定义窗口拓展 : EditorWindow
{
    private void OnGUI()
    {
        GUILayout.Label("测试文本");
        if (GUILayout.Button("测试按钮"))
        {
            Debug.Log("Test");
        }
    }
}

2.2显示窗口

我们可以使用添加自定义页签的方式来开启窗口,这需要通过调用 EditorWindow.GetWindow 方法来创建窗口对象。该方法有多种重载形式,主要参数包括:

  1. Type 或 T:指定窗口类的类型。
  2. utility:若为 true,可创建浮动实用程序窗口(这种窗口可自由拖动和改变大小);若为 false,则创建正常窗口。
  3. title:用于设置窗口标题。
  4. focus:决定是否为窗口提供焦点(若窗口已存在),新创建的窗口始终会获得焦点。
  5. desiredDockNextTo:表示窗口试图停靠到其上的 EditorWindow 类型的数组。

创建窗口对象后,调用其 Show 方法即可显示窗口。示例代码如下:

using UnityEditor;

public class Lesson03_自定义窗口拓展 : EditorWindow
{
    [MenuItem("编辑器拓展教程/Lesson03_自定义窗口拓展/显示Lesson03自定义窗口")]
    private static void ShowWindow()
    {
        Lesson03_自定义窗口拓展 win = EditorWindow.GetWindow<Lesson03_自定义窗口拓展>();
        win.titleContent = new GUIContent("我的窗口");
        win.Show();
    }

    // 其他代码...
}

2.3.窗口事件回调函数

继承 EditorWindow 的窗口类自带一些事件回调函数,当相应事件触发时会自动执行:

回调函数 触发时机 示例代码
OnHierarchyChange() 当场景中的层次结构(Hierarchy)发生变化,如游戏对象的创建、删除或重命名时调用。 private void OnHierarchyChange() { Debug.Log("当Hierarchy窗口内容发生变化时"); }
OnFocus() 窗口获得焦点时调用,可在此执行相关操作。 private void OnFocus() { Debug.Log("获取焦点"); }
OnLostFocus() 窗口失去焦点时调用,常用于执行清理工作。 private void OnLostFocus() { Debug.Log("失去焦点"); }
OnProjectChange() 项目资源发生变化,如添加、删除或修改项目文件时调用。 private void OnProjectChange() { Debug.Log("当Project窗口内容发生变化时"); }
OnInspectorUpdate() 检视器(Inspector)面板更新时调用,可用于更新显示信息。 private void OnInspectorUpdate() { Debug.Log("当Inspector窗口内容发生变化时"); }
OnSelectionChange() 选择的对象发生变化时调用,可执行与所选对象相关的操作。 private void OnSelectionChange() { Debug.Log("当选中对象发生变化时"); }

2.4.窗口中常用的生命周期函数

生命周期函数 触发时机 用途 示例代码
OnEnable() 窗口被激活时调用,通常在窗口创建时执行一次,用于进行初始化工作,如注册事件监听器或设置初始变量。 进行初始化操作 private void OnEnable() { // 初始化操作 }
OnGUI() 每帧都会调用,用于绘制编辑器窗口的 GUI,使用 GUILayoutEditorGUILayout 等类创建界面元素。 绘制界面相关元素 private void OnGUI() { // 绘制界面元素 }
OnDestroy() 窗口被销毁时调用,如关闭编辑器或切换场景时触发,用于进行最终的清理工作,释放未释放的资源。 执行清理操作 private void OnDestroy() { // 清理操作 }
Update() 编辑器窗口每帧更新时调用,用于执行每帧需要进行的逻辑。 处理每帧相关逻辑 private void Update() { // 每帧逻辑 }

2.5.编辑器窗口类中的常用成员

静态变量

静态变量 描述 示例代码
focusedWindow 当前已获得键盘焦点的 EditorWindow(只读)。 EditorWindow currentFocusedWindow = EditorWindow.focusedWindow;
mouseOverWindow 当前在鼠标光标下的 EditorWindow(只读)。 EditorWindow currentMouseOverWindow = EditorWindow.mouseOverWindow;

静态函数

静态函数 描述 示例代码
CreateWindow 创建窗口,可用于创建非单例唯一的窗口。 Lesson03_自定义窗口拓展 newWindow = EditorWindow.CreateWindow();
GetWindow 创建单例唯一的窗口对象。 Lesson03_自定义窗口拓展 singletonWindow = EditorWindow.GetWindow();
GetWindowWithRect 返回一个指定位置、大小的窗口。 Rect rect = new Rect(100, 100, 200, 200); Lesson03_自定义窗口拓展 sizedWindow = EditorWindow.GetWindowWithRect(rect);
HasOpenInstances 检查编辑器窗口是否打开。 bool isOpen = EditorWindow.HasOpenInstances();

成员变量

成员变量 描述 示例代码
titleContent 用于设置窗口标题名。 win.titleContent = new GUIContent("新标题");
position 存储窗口的位置和大小信息。 Rect currentPos = win.position; win.position = new Rect(200, 200, 300, 300);
wantsMouseEnterLeaveWindow 若设置为 true,鼠标进入或离开窗口时,窗口会收到一次 OnGUI 调用。 win.wantsMouseEnterLeaveWindow = true;

成员函数

成员函数 描述 示例代码
Show 显示面板。 win.Show();
Repaint 重绘窗口。 win.Repaint();
Close 关闭窗口。 win.Close();

3.EditorGUI

3.1. EditorWindow 类成员

静态变量

变量名 描述 示例代码
focusedWindow 当前获得键盘焦点的 EditorWindow(只读) EditorWindow currentFocusedWindow = EditorWindow.focusedWindow;
mouseOverWindow 当前鼠标光标下的 EditorWindow(只读) EditorWindow currentMouseOverWindow = EditorWindow.mouseOverWindow;

静态函数

函数名 描述 示例代码
CreateWindow 创建非单例唯一的窗口 Lesson03_自定义窗口拓展 newWindow = EditorWindow.CreateWindow();
GetWindow 创建单例唯一的窗口对象 Lesson03_自定义窗口拓展 singletonWindow = EditorWindow.GetWindow();
GetWindowWithRect 返回指定位置、大小的窗口 Rect rect = new Rect(100, 100, 200, 200); Lesson03_自定义窗口拓展 sizedWindow = EditorWindow.GetWindowWithRect(rect);
HasOpenInstances 检查编辑器窗口是否打开 bool isOpen = EditorWindow.HasOpenInstances();

成员变量

变量名 描述 示例代码
titleContent 设置窗口标题名 win.titleContent = new GUIContent("新标题");
position 存储窗口位置和大小信息 Rect currentPos = win.position; win.position = new Rect(200, 200, 300, 300);
wantsMouseEnterLeaveWindow 设为 true 时,鼠标进出窗口会收到一次 OnGUI 调用 win.wantsMouseEnterLeaveWindow = true;

成员函数

函数名 描述 示例代码
Show 显示面板 win.Show();
Repaint 重绘窗口 win.Repaint();
Close 关闭窗口 win.Close();

3.2. EditorGUILayout 相关功能

布局选项

类型 描述 示例代码
固定宽高 设置控件固定宽度和高度 GUILayout.Width(300); GUILayout.Height(200);
最小宽高 设置控件最小宽度和高度 GUILayout.MinWidth(50); GUILayout.MinHeight(50);
最大宽高 设置控件最大宽度和高度 GUILayout.MaxWidth(100); GUILayout.MaxHeight(100);
水平拓展 设置控件水平拓展属性 GUILayout.ExpandWidth(true); GUILayout.ExpandHeight(false);

文本与选择控件

控件类型 子类型 描述 示例代码
文本控件 带标题内容文本 显示带标题和内容的文本 EditorGUILayout.LabelField("文本标题", "测试内容");
普通文本 显示普通文本 EditorGUILayout.LabelField("文本内容");
层级、标签选择 层级选择 选择游戏对象层级 int变量 = EditorGUILayout.LayerField("层级选择", int变量);
标签选择 选择游戏对象标签 string变量 = EditorGUILayout.TagField("标签选择", string变量);
枚举选择控件 枚举单选 单选枚举值 枚举变量 = (枚举类型)EditorGUILayout.EnumPopup("枚举选择", 枚举变量);
枚举多选 多选枚举值 枚举变量 = (枚举类型)EditorGUILayout.EnumFlagsField("枚举多选", 枚举变量);
整数选择控件 整数单选 从给定选项中单选整数 int变量 = EditorGUILayout.IntPopup("整数单选框", int变量, 字符串数组, int数组);

输入与关联控件

控件类型 子类型 描述 示例代码
各类型输入控件 数值输入 输入不同数值类型 int变量 = EditorGUILayout.IntField("Int输入框", int变量);
long变量 = EditorGUILayout.LongField("long输入框", long变量);
float变量 = EditorGUILayout.FloatField("Float 输入:", float变量);
double变量 = EditorGUILayout.DoubleField("double 输入:", double变量);
文本及向量输入 输入文本和向量 string变量 = EditorGUILayout.TextField("Text输入:", string变量);
vector2变量 = EditorGUILayout.Vector2Field("Vec2输入: ", vector2变量);
vector3变量 = EditorGUILayout.Vector3Field("Vec3输入: ", vector3变量);
vector4变量 = EditorGUILayout.Vector4Field("Vec4输入: ", vector4变量);
rect变量 = EditorGUILayout.RectField("rect输入: ", rect变量);
bounds变量 = EditorGUILayout.BoundsField("Bounds输入: ", bounds变量);
boundsInt变量 = EditorGUILayout.BoundsIntField("Bounds输入: ", boundsInt变量);
Delayed输入控件 输入值延迟生效 i2 = EditorGUILayout.DelayedIntField("Int输入框", i2);
对象关联控件 - 关联游戏对象或资源对象 对象变量 = EditorGUILayout.ObjectField(对象变量, typeof(对象类型), 是否允许关联场景上对象资源) as 对象类型;

交互与提示控件

控件类型 子类型 描述 示例代码
按钮控件 按下触发按钮 按下按钮触发操作 EditorGUILayout.DropdownButton(new GUIContent("按钮上文字"), FocusType.Passive)
开关控件 普通开关 普通开关按钮 bool变量 = EditorGUILayout.Toggle("普通开关", bool变量);
开关在左侧 开关在文字左侧的按钮 bool变量 = EditorGUILayout.ToggleLeft("开关在左侧", bool变量);
开关组控件 - 一组相关开关 bool变量 = EditorGUILayout.BeginToggleGroup("开关组", bool变量); 其他控件绘制 EditorGUILayout.EndToggleGroup();
滑动条控件 浮点滑动条 选择浮点数值范围 float变量 = EditorGUILayout.Slider("滑动条", float变量, 最小值, 最大值);
整数滑动条 选择整数值范围 int变量 = EditorGUILayout.IntSlider("整数值滑动条", int变量, 最小值, 最大值);
双块滑动条控件 - 选择数值范围区间 EditorGUILayout.MinMaxSlider("双块滑动条", ref 左侧值, ref 右侧值, 最小值, 最大值);
帮助框控件 一般提示 显示一般提示信息 EditorGUILayout.HelpBox("一般提示", MessageType.None);
感叹号提示 显示带感叹号提示信息 EditorGUILayout.HelpBox("感叹号提示", MessageType.Info);
警告符号提示 显示带警告符号提示信息 EditorGUILayout.HelpBox("警告符号提示", MessageType.Warning);
错误符号提示 显示带错误符号提示信息 EditorGUILayout.HelpBox("错误符号提示", MessageType.Error);

其他控件

控件类型 描述 示例代码
折叠控件 普通折叠和折叠组,用于展开或收起内容 普通折叠:bool变量 = EditorGUILayout.Foldout(bool变量, "标题名");
折叠组:bool变量 = EditorGUILayout.BeginFoldoutHeaderGroup(bool变量, "标题名"); EditorGUILayout.EndFoldoutHeaderGroup();
间隔控件 在布局中添加间隔 EditorGUILayout.Space(10);
动画曲线控件 编辑动画曲线 AnimationCurve变量 = EditorGUILayout.CurveField("动画曲线:", AnimationCurve变量);
布局相关API 水平、垂直布局和滚动视图布局 水平布局:EditorGUILayout.BeginHorizontal(); 一大堆控件 EditorGUILayout.EndHorizontal();
垂直布局:EditorGUILayout.BeginVertical(); 一大堆控件 EditorGUILayout.EndVertical();
滚动视图:Vector2布局 = EditorGUILayout.BeginScrollView(Vector2布局); 一大堆控件 EditorGUILayout.EndScrollView();

4.EditorGUIUtility

4.1 资源加载

用于加载放置在Editor Default Resources文件夹中的资源。

方法名 描述 示例代码
EditorGUIUtility.Load(string path) 根据指定路径加载资源,路径需包含后缀名。资源不存在时返回null var texture = EditorGUIUtility.Load("exampleTexture.png") as Texture2D;
EditorGUIUtility.LoadRequired(string path) 根据指定路径加载资源,路径需包含后缀名。资源不存在时直接报错 var font = EditorGUIUtility.LoadRequired("exampleFont.ttf") as Font;
  • 注意事项
    • 资源路径必须是Assets/Editor Default Resources/文件夹下的相对路径。
    • 使用LoadRequired方法时需确保资源存在,否则会中断程序并报错。

4.2 搜索框查询对象选中提示

作用:弹出搜索窗口选择资源,获取选择对象并监听选择事件。

方法名 描述 示例代码
EditorGUIUtility.ShowObjectPicker(UnityEngine.Object obj, bool allowSceneObjects, string filter, int controlID) 显示对象选择器窗口。T为资源类型,obj为默认选中对象引用,allowSceneObjects决定是否允许选择场景对象,filter用于过滤对象名称,controlID一般设为0 EditorGUIUtility.ShowObjectPicker(null, false, "", 0);
EditorGUIUtility.GetObjectPickerObject() 获取在对象选择器中选中的对象 var selectedObj = EditorGUIUtility.GetObjectPickerObject();
Event.current 获取当前发生的事件 var currentEvent = Event.current;
Event.current.commandName 获取当前事件的命令名称
ObjectSelectorUpdated:对象选择发生变化时发送
ObjectSelectorClosed:对象选择窗口关闭时发送
var commandName = Event.current.commandName;
if (Event.current.commandName == "ObjectSelectorUpdated"){ // 当选择发生更新时通知进入}
else if (Event.current.commandName == "ObjectSelectorClosed"){ // 当选择窗口关闭时通知进入}
EditorGUIUtility.PingObject(obj); 对象选中提示,obj为需要选中的物体 EditorGUIUtility.PingObject(img3);
  • 注意事项
    • 设置EditorGUIUtility.ShowObjectPicker参数时,根据实际需求准确配置,如allowSceneObjects影响可选择对象范围。
    • 通过监听Event.current.commandName中的ObjectSelectorUpdated(对象选择变化)和ObjectSelectorClosed(选择窗口关闭)事件,实现对选择行为的响应。

4.3 窗口事件传递坐标转换

作用:实现窗口间事件传递,并在屏幕坐标系和GUI坐标系间进行坐标转换。

方法名 描述 示例代码
EditorGUIUtility.CommandEvent(string commandName) 发送指定名称的命令事件 EditorGUIUtility.CommandEvent("SomeCustomCommand");
win.SendEvent(Event e) 将事件发送到指定窗口。win为目标窗口,e为要发送的事件 MyEditorWindow win = GetWindow(); win.SendEvent(Event.current);
Event.current.type 判断当前事件的类型 if(Event.current.type == EventType.ExecuteCommand) { /* 执行相关逻辑 */ }
Event.current.commandName 判断当前执行的事件命令名称 if(Event.current.commandName == "SomeCustomCommand") { /* 执行相关逻辑 */ }
EditorGUIUtility.GUIToScreenPoint(Vector2 guiPoint) 将GUI坐标系中的点转换为屏幕坐标系中的点 Vector2 screenPoint = EditorGUIUtility.GUIToScreenPoint(new Vector2(100, 100));
EditorGUIUtility.GUIToScreenRect(Rect guiRect) 将GUI坐标系中的矩形转换为屏幕坐标系中的矩形 Rect screenRect = EditorGUIUtility.GUIToScreenRect(new Rect(100, 100, 200, 200));
EditorGUIUtility.ScreenToGUIPoint(Vector2 screenPoint) 将屏幕坐标系中的点转换为GUI坐标系中的点 Vector2 guiPoint = EditorGUIUtility.ScreenToGUIPoint(new Vector2(500, 500));
EditorGUIUtility.ScreenToGUIRect(Rect screenRect) 将屏幕坐标系中的矩形转换为GUI坐标系中的矩形 Rect guiRect = EditorGUIUtility.ScreenToGUIRect(new Rect(500, 500, 300, 300));
  • 注意事项
    • 事件传递会自动打开目标窗口并转移焦点。
    • 进行坐标转换时,若在布局函数中,需考虑布局偏移对坐标的影响,且多显示器环境下坐标计算会涉及多个显示器。

4.4 指定区域使用对应鼠标指针

作用:在指定区域设置特定的鼠标指针样式。

方法名 描述 示例代码
EditorGUIUtility.AddCursorRect(Rect position, MouseCursor mouse) 在指定矩形区域内设置鼠标指针样式。position为区域矩形,mouse为鼠标光标类型枚举值 EditorGUIUtility.AddCursorRect(new Rect(0, 0, 100, 100), MouseCursor.Text);

鼠标指针样式
MouseCursor枚举包含多种光标类型,如Arrow(箭头)、Text(文本输入光标)、ResizeVertical(垂直调整大小光标)等。

枚举值 描述
Arrow 普通指针箭头
Text 文本文本光标
ResizeVertical 调整大小垂直调整大小箭头
ResizeHorizontal 调整大小水平调整大小箭头
Link 带有链接徽章的链接箭头
SlideArrow 滑动箭头带有小箭头的箭头,用于指示在数字字段处滑动
ResizeUpRight 调整大小向上向右调整窗口边缘的大小
ResizeUpLeft 调整大小向上向左调整窗口边缘的大小
MoveArrow 带有移动符号的箭头,用于场景视图
RotateArrow 旁边有用于场景视图的旋转符号的箭头
ScaleArrow 旁边有用于场景视图的缩放符号的箭头
ArrowPlus 旁边带有加号的箭头
ArrowMinus 旁边带有减号的箭头
Pan 用拖动的手拖动光标进行平移
Orbit 用眼睛观察轨道的光标
Zoom 使用放大镜进行缩放的光标
FPS 带眼睛的光标和用于FPS导航的样式化箭头键
CustomCursor 当前用户定义的光标
SplitResizeUpDown 向上 - 向下调整窗口拆分器的大小箭头
SplitResizeLeftRight 窗口拆分器的左 - 右调整大小箭头

4.5 绘制色板绘制曲线

作用:在指定区域绘制色板和曲线,辅助颜色和曲线相关的编辑展示。

方法名 描述 示例代码
EditorGUIUtility.DrawColorSwatch(Rect rect, Color color) 在指定矩形区域绘制色板。rect为绘制区域,color为要绘制的颜色 EditorGUIUtility.DrawColorSwatch(new Rect(100, 100, 50, 50), Color.red);
EditorGUIUtility.DrawCurveSwatch(Rect rect, AnimationCurve curve, SerializedProperty property, Color curveColor, Color backgroundColor) 在指定矩形区域绘制曲线。rect为绘制范围,curve为动画曲线,property可为SerializedProperty类型的曲线(可为null),curveColor为曲线颜色,backgroundColor为背景颜色 AnimationCurve curve = new AnimationCurve();
curve.AddKey(0, 0);
curve.AddKey(1, 1); EditorGUIUtility.DrawCurveSwatch(new Rect(200, 200, 100, 100), curve, null, Color.blue, Color.white);
  • 注意事项
    • 绘制色板常与EditorGUILayout.ColorField配合,为颜色选择提供直观展示。
    • 绘制曲线常与EditorGUILayout.CurveField配合,用于动画曲线编辑场景的可视化辅助。

5.Selection

获取选择对象的属性

属性 描述 示例代码
Selection.activeObject 获取当前在面板上选择的游戏物体 Object,未选择则返回 Null,选择多个则返回第一个选择的游戏物体 var obj = Selection.activeObject;
Selection.activeGameObject 获取当前在面板上选择的游戏物体 GameObject,未选择或者选择的不是游戏对象则返回 Null,选择多个则返回第一个选择的游戏物体 var go = Selection.activeGameObject;
Selection.activeTransform 获取当前在面板上选择的游戏物体的 Transform(只能获取 Hierarchy 窗口的对象),未选择则返回 Null,选择多个则返回第一个选择的游戏物体 var trans = Selection.activeTransform;
Selection.objects 获取当前在面板上选择的物体数组,未选择则返回 Null var objs = Selection.objects;
Selection.gameObjects 获取当前选择的所有 GameObject,未选择则返回 Null,可遍历获取所有信息 var gos = Selection.gameObjects;
Selection.transforms 获取当前选择的所有 Transform,未选择则返回 Null,可遍历获取所有信息 var transs = Selection.transforms;

常用静态方法

方法 描述 参数说明 示例代码
Selection.Contains 判断某个对象是否被选中(多选中存在也算) obj:要判断的对象 Selection.Contains(obj);
Selection.GetFiltered 从当前选择对象中,筛选出想要的内容 类型:要筛选的对象类型;筛选模式SelectionMode 枚举值,可通过位或 ` 混用
Selection.selectionChanged(委托) 当选中变化时会调用的委托 Selection.selectionChanged += () => Debug.Log("Selection changed");

筛选模式
SelectionMode枚举定义了不同的筛选模式,具体如下:

筛选模式 描述
Unfiltered 不过滤,返回所有选中对象。
TopLevel 只获取最上层对象,子对象不获取。
Deep 父对象和子对象都获取。
ExcludePrefab 排除预设体。
Editable 只选择可编辑的对象。
OnlyUserModifiable 仅返回用户可修改的内容。
Assets 只返回资源文件夹下的内容。
DeepAssets 如果存在子文件夹,其中的内容也会获取。

若要同时使用多种筛选模式,可通过位或运算符|来组合。

  • 示例 1:运用Selection.GetFiltered(SelectionMode.Unfiltered)获取所有选中的GameObject
  • 示例 2:使用Selection.GetFiltered(SelectionMode.DeepAssets)获取资源文件夹及其子文件夹下所有选中的Texture2D
  • 示例 3:通过Selection.GetFiltered(typeof(GameObject), SelectionMode.TopLevel | SelectionMode.Editable)获取可编辑的最上层GameObject,此处结合了TopLevelEditable两种筛选模式。

6.Event

属性/方法 描述 示例代码
Event.current 获取当前正在处理的事件 Event eventCurrent = Event.current;
event.alt 判断 Alt 键是否按下 if (eventCurrent.alt) Debug.Log("alt 键按下了");
event.shift 判断 Shift 键是否按下 if (eventCurrent.shift) Debug.Log("shift 键按下了");
event.control 判断 Ctrl 键是否按下 if (eventCurrent.control) Debug.Log("control 键按下了");
event.isMouse 判断当前事件是否为鼠标事件 if (eventCurrent.isMouse) { Debug.Log("鼠标相关事件"); }
event.button 若为鼠标事件,可获取鼠标按键(左、中、右) if (eventCurrent.isMouse) { Debug.Log(eventCurrent.button); }
event.mousePosition 若为鼠标事件,可获取鼠标位置 if (eventCurrent.isMouse) { Debug.Log("鼠标位置" + eventCurrent.mousePosition); }
event.isKey 判断当前事件是否为键盘事件 if (eventCurrent.isKey) { Debug.Log("键盘相关事件"); }
event.character 若为键盘事件,可获取输入的字符 if (eventCurrent.isKey) { Debug.Log(eventCurrent.character); }
event.keyCode 若为键盘事件,可获取对应的 KeyCode if (eventCurrent.isKey) { switch (eventCurrent.keyCode) { case KeyCode.Space: Debug.Log("空格键输入"); break; } }
event.capsLock 判断大小写锁定是否开启 if (eventCurrent.capsLock) Debug.Log("大小写锁定开启"); else Debug.Log("大小写锁定关闭");
event.command 判断 Windows 键或 MacCommand 键是否按下 if (eventCurrent.command) Debug.Log("PC win 键按下 或 Mac Command 键按下");
event.commandName 用于判断是否触发了特定的键盘事件,如复制、粘贴、剪切等 if (eventCurrent.commandName == "Copy") { Debug.Log("按下了 ctrl + c"); } if (eventCurrent.commandName == "Paste") { Debug.Log("按下了 ctrl + v"); } if (eventCurrent.commandName == "Cut") { Debug.Log("按下了 ctrl + x"); }
event.functionKey 判断是否输入了功能键(如方向键、Page UpPage Down 等) if (eventCurrent.functionKey) Debug.Log("有功能按键输入");
event.numeric 判断小键盘是否开启 if (eventCurrent.numeric) Debug.Log("小键盘是否开启");
event.Use() 在处理完当前事件后,阻止事件继续派发,避免与 Unity 其他编辑器事件逻辑冲突 eventCurrent.Use();

7.Inspector窗口拓展

通过这个特性[CustomEditor(typeof(TestInspectorMono))],我们就可以为TestInspectorMono脚本自定义Inspector窗口中的显示了

7.1.方法和参数

方法 参数 描述与用途 示例代码
SerializedObject.FindProperty(string propertyPath) propertyPath:字符串类型,要查找的属性路径 在自定义编辑器脚本中,通过指定路径查找序列化对象中的属性,用于关联自定义脚本中的成员。 SerializedObject so = new SerializedObject(target); SerializedProperty sp = so.FindProperty("myProperty");
SerializedProperty.FindPropertyRelative(string propertyName) propertyName:字符串类型,要查找的子属性名称 在自定义显示自定义数据结构类相关内容时,查找相对于当前属性的指定名称的子属性,方便获取子属性进行后续操作。 SerializedProperty parentProp = serializedObject.FindProperty("parentProp"); SerializedProperty childProp = parentProp.FindPropertyRelative("childProp");
serializedObject.ApplyModifiedProperties() 将对序列化属性所做的修改应用到目标对象上,在使用 SerializedProperty 修改属性值后,调用此方法可使修改生效。 serializedObject.Update(); SerializedProperty prop = serializedObject.FindProperty("myProp"); prop.intValue = 10; serializedObject.ApplyModifiedProperties();
SerializedProperty.arraySize 在处理数组或List属性自定义显示时,获取数组或List类型属性的容量,以便根据容量进行相关操作。 SerializedProperty listProp = serializedObject.FindProperty("myList"); int size = listProp.arraySize;
SerializedProperty.InsertArrayElementAtIndex(int index) index:整数类型,要插入元素的索引位置 在自定义显示数组或List时,为数组在指定索引位置插入默认元素,实现扩容操作,以满足自定义显示需求。 SerializedProperty arrProp = serializedObject.FindProperty("myArray"); arrProp.InsertArrayElementAtIndex(2);
SerializedProperty.DeleteArrayElementAtIndex(int index) index:整数类型,要删除元素的索引位置 在自定义显示数组或List时,删除数组中指定索引位置的元素,实现缩减容量操作,以满足自定义显示需求。 SerializedProperty arrProp = serializedObject.FindProperty("myArray"); arrProp.DeleteArrayElementAtIndex(1);
SerializedProperty.GetArrayElementAtIndex(int index) index:整数类型,要获取元素的索引位置 在自定义显示数组或List时,获取数组中指定索引位置的SerializedProperty对象,用于对特定位置元素进行编辑或显示。 SerializedProperty arrProp = serializedObject.FindProperty("myArray"); SerializedProperty elementProp = arrProp.GetArrayElementAtIndex(0);
EditorGUILayout.PropertyField(SerializedProperty property, GUIContent label) propertySerializedProperty类型,要显示的属性对象;labelGUIContent类型,属性的标题内容 在自定义Inspector窗口,按照属性类型自动处理控件绘制逻辑,显示指定的序列化属性,方便用户查看和编辑。 SerializedProperty prop = serializedObject.FindProperty("myProp"); EditorGUILayout.PropertyField(prop, new GUIContent("My Prop"));

7.2.重写

OnInspectorGUI函数内逻辑

  • 描述与用途:在该函数内部处理各种绘制和交互逻辑,根据不同的用户操作(如按钮点击)和状态变化(如属性值改变)进行相应处理,实现Inspector窗口的定制化交互和显示。
  • 示例代码
public override void OnInspectorGUI()
{
    if (GUILayout.Button("Click Me"))
    {
        Debug.Log("Button Clicked");
    }
    serializedObject.Update();
    SerializedProperty prop = serializedObject.FindProperty("myProp");
    EditorGUILayout.PropertyField(prop);
    serializedObject.ApplyModifiedProperties();
}

7.3.接口

ISerializationCallbackReceiver接口

  • 描述与用途:用于处理不被Unity默认支持在Inspector窗口显示的数据结构(如Dictionary),通过在对象序列化和反序列化时执行自定义逻辑,实现对这些数据结构在Inspector窗口的间接编辑和显示。
  • 接口函数
    • OnBeforeSerialize:在对象被序列化之前调用。将对象中的数据转换为可序列化的形式,比如将Dictionary数据存储到两个List中,以便在Inspector窗口中显示和存储。
    • OnAfterDeserialize:在对象从磁盘反序列化后调用。将反序列化后的数据恢复到对象的原始数据结构中,比如从两个List中读取数据填充到Dictionary中。
  • 示例代码
using UnityEngine;
using System;
using System.Collections.Generic;

public class MyClass : MonoBehaviour, ISerializationCallbackReceiver
{
    public Dictionary<int, string> myDic = new Dictionary<int, string>();
    [SerializeField] private List<int> keys = new List<int>();
    [SerializeField] private List<string> values = new List<string>();

    public void OnBeforeSerialize()
    {
        keys.Clear();
        values.Clear();
        foreach (var item in myDic)
        {
            keys.Add(item.Key);
            values.Add(item.Value);
        }
    }

    public void OnAfterDeserialize()
    {
        myDic.Clear();
        for (int i = 0; i < keys.Count; i++)
        {
            myDic.Add(keys[i], values[i]);
        }
    }
}

8.Handles

8.1.方法

方法 描述 示例代码
Handles.Label(位置, 文本内容) 在指定位置绘制文本 Handles.Label(Vector3.zero, "示例文本");
Handles.DrawLine(起点, 终点, 粗细) 在两点间绘制线段 Handles.DrawLine(Vector3.zero, new Vector3(1, 0, 0), 2f);
Handles.DrawDottedLine(起点, 终点, 粗细) 在两点间绘制虚线 Handles.DrawDottedLine(Vector3.zero, new Vector3(0, 0, 3), 3f);
Handles.DrawWireArc(圆心, 法线, 绘制朝向, 角度, 半径) 绘制线框弧线 Handles.DrawWireArc(Vector3.zero, Vector3.up, Vector3.forward, 60, 4f);
Handles.DrawSolidArc(圆心, 法线, 绘制朝向, 角度, 半径) 绘制填充弧线 Handles.DrawSolidArc(Vector3.zero, Vector3.up, Vector3.right, 45, 3f);
Handles.DrawSolidDisc(圆心, 法线, 半径) 绘制填充圆 Handles.DrawSolidDisc(Vector3.zero, Vector3.up, 2.5f);
Handles.DrawWireDisc(圆心, 法线, 半径) 绘制线框圆 Handles.DrawWireDisc(Vector3.zero, Vector3.up, 3.5f);
Handles.DrawWireCube(中心点, xyz大小) 绘制立方体线框 Handles.DrawWireCube(Vector3.zero, new Vector3(1, 1, 1));
Handles.DrawAAConvexPolygon(几何体各顶点) 绘制几何体 Handles.DrawAAConvexPolygon(Vector3.zero, Vector3.right, new Vector3(1, 1, 0));
Handles.DoPositionHandle(位置, 角度) 显示并处理移动轴控制柄 Vector3 newPosition = Handles.DoPositionHandle(Vector3.zero, Quaternion.identity);
Handles.PositionHandle(位置, 角度) 显示并处理移动轴控制柄 Vector3 newPosition = Handles.PositionHandle(Vector3.zero, Quaternion.identity);
Handles.DoRotationHandle(角度, 位置) 显示并处理旋转轴控制柄 Quaternion newRotation = Handles.DoRotationHandle(Quaternion.identity, Vector3.zero);
Handles.RotationHandle(角度, 位置) 显示并处理旋转轴控制柄 Quaternion newRotation = Handles.RotationHandle(Quaternion.identity, Vector3.zero);
Handles.DoScaleHandle(缩放, 位置, 角度, HandleUtility.GetHandleSize(位置)) 显示并处理缩放轴控制柄 Vector3 newScale = Handles.DoScaleHandle(new Vector3(1, 1, 1), Vector3.zero, Quaternion.identity, HandleUtility.GetHandleSize(Vector3.zero));
Handles.ScaleHandle(缩放, 位置, 角度, HandleUtility.GetHandleSize(位置)) 显示并处理缩放轴控制柄 Vector3 newScale = Handles.ScaleHandle(new Vector3(1, 1, 1), Vector3.zero, Quaternion.identity, HandleUtility.GetHandleSize(Vector3.zero));
Handles.FreeMoveHandle(位置, 句柄大小, 移动步进值, 渲染控制手柄的回调函数) 显示自由移动控制柄 Vector3 newFreePosition = Handles.FreeMoveHandle(Vector3.zero, 1f, new Vector3(0.1f, 0.1f, 0.1f), Handles.RectangleHandleCap);
Handles.FreeRotateHandle(角度, 位置, 句柄大小) 显示自由旋转控制柄 Quaternion newFreeRotation = Handles.FreeRotateHandle(Quaternion.identity, Vector3.zero, 1f);
Handles.BeginGUI() 开始在 Scene 视图中绘制 GUI Handles.BeginGUI();
Handles.EndGUI() 结束在 Scene 视图中绘制 GUI Handles.EndGUI();
HandleUtility.GetHandleSize(Vector3 position) 获取在场景中给定位置的句柄的合适尺寸 float handleSize = HandleUtility.GetHandleSize(Vector3.zero);
HandleUtility.WorldToGUIPoint(Vector3 worldPosition) 将世界坐标转换为 GUI 坐标 Vector2 guiPos = HandleUtility.WorldToGUIPoint(Vector3.zero);
HandleUtility.GUIPointToWorldRay(Vector2 position) 将屏幕上的像素坐标转换为射线 Ray ray = HandleUtility.GUIPointToWorldRay(new Vector2(0, 0));
HandleUtility.DistanceToLine(Vector3 lineStart, Vector3 lineEnd) 计算场景中一条线段与鼠标光标的最短距离 float dis = HandleUtility.DistanceToLine(Vector3.zero, new Vector3(1, 0, 0));
HandleUtility.PickGameObject(Vector2 position, bool isSelecting) 在编辑器中根据鼠标位置进行对象的拾取 GameObject pickedObj = HandleUtility.PickGameObject(new Vector2(0, 0), true);

8.2. 静态参数

静态参数 描述
Handles color 在调用 Handles 中的绘制 API 之前,可设置此颜色属性来指定绘制图形的颜色,如 Handles.color = new Color(0, 1, 0, 1f); 可将后续绘制的图形颜色设为绿色

9.Gizmos

9.1.方法

方法 描述 示例代码
Gizmos.DrawCube(中心点, 大小) 绘制实心立方体 Gizmos.DrawCube(Vector3.zero, Vector3.one);
Gizmos.DrawWireCube(中心点, 大小) 绘制立方体线框 Gizmos.DrawWireCube(this.transform.position, new Vector3(2, 1, 3));
Gizmos.DrawFrustum(绘制中心, FOV角度, 远裁切平面, 近裁切平面, 屏幕长宽比) 绘制视锥 Gizmos.DrawFrustum(this.transform.position, 30, 50, 0.5f, 1.7f);
Gizmos.DrawSphere(中心点, 半径) 绘制实心球体 Gizmos.DrawSphere(this.transform.position, 2);
Gizmos.DrawWireSphere(中心点, 半径) 绘制球体线框 Gizmos.DrawWireSphere(this.transform.position, 3);
Gizmos.DrawWireMesh(mesh, 位置, 角度) 绘制网格线 if (mesh != null) Gizmos.DrawWireMesh(mesh, this.transform.position, this.transform.rotation);
Gizmos.DrawGUITexture(new Rect(x, y, w, h), 图片信息) 绘制贴图 if (pic != null) Gizmos.DrawGUITexture(new Rect(this.transform.position.x, this.transform.position.y, 160, 90), pic);
Gizmos.DrawIcon(Vector3位置, “图标名”) 绘制图标,图标需放在Assets/Gizmos/文件夹中 Gizmos.DrawIcon(this.transform.position, "MyIcon");
Gizmos.DrawLine(起点, 终点) 绘制线段 Gizmos.DrawLine(this.transform.position, this.transform.position + Vector3.one);
Gizmos.DrawMesh(mesh, 位置, 角度) 绘制网格 if (mesh != null) Gizmos.DrawMesh(mesh, this.transform.position, this.transform.rotation);
Gizmos.DrawRay(起点, 方向) 绘制射线 Gizmos.DrawRay(this.transform.position, this.transform.forward);

9.2. 静态参数

静态参数 描述 示例代码
Gizmos color 修改 Gizmos 绘制图形的颜色 Gizmos.color = Color.green;
Gizmos matrix 修改 Gizmos 绘制前的矩阵,可改变绘制内容的角度、位置和缩放,使用 Matrix4x4.identity 可还原矩阵 Gizmos.matrix = Matrix4x4.TRS(this.transform.position, this.transform.rotation, Vector3.one);
Gizmos.matrix = Matrix4x4.identity;

9.3. 响应函数

每帧调用,绘制的内容随时可在 Scene 窗口中看见

private void OnDrawGizmos()
{
    Debug.Log("Gizmos");
}

仅当脚本依附的 GameObject 被选中时才会每帧调用绘制相关内容 |

private void OnDrawGizmosSelected()
{
    Debug.Log("Gizmos2");
}

10.EditorUtility

方法 描述 返回值 示例代码
EditorUtility.DisplayDialog 显示含确定按钮的提示窗口,阻塞逻辑 bool if (EditorUtility.DisplayDialog("标题", "信息", "确定")) Debug.Log("点击确定");
EditorUtility.DisplayDialogComplex 显示三按钮提示面板,阻塞逻辑 int int res = EditorUtility.DisplayDialogComplex("标题", "信息", "按钮1", "按钮2", "按钮3");
EditorUtility.DisplayProgressBar 显示进度条,不阻塞逻辑 void EditorUtility.DisplayProgressBar("进度条", "信息", 0.5f);
EditorUtility.ClearProgressBar 关闭进度条 void EditorUtility.ClearProgressBar();
EditorUtility.SaveFilePanel 显示文件存储面板 string string path = EditorUtility.SaveFilePanel("标题", "", "文件名", "后缀");
EditorUtility.SaveFilePanelInProject 显示项目内文件存储面板 string string path = EditorUtility.SaveFilePanelInProject("标题", "文件名", "后缀", "摘要");
EditorUtility.SaveFolderPanel 显示文件夹存储面板 string string path = EditorUtility.SaveFolderPanel("标题", "", "默认名");
EditorUtility.OpenFilePanel 显示打开文件面板 string string path = EditorUtility.OpenFilePanel("标题", "", "后缀");
EditorUtility.OpenFolderPanel 显示打开文件夹面板 string string path = EditorUtility.OpenFolderPanel("标题", "", "默认名");
EditorUtility.CompressTexture 压缩纹理到指定格式 void EditorUtility.CompressTexture(texture, format, quality);
EditorUtility.CollectDependencies 查找对象依赖资源列表 object[] object[] deps = EditorUtility.CollectDependencies(new Object[] { obj });
  • 注意事项
    • DisplayDialogDisplayDialogComplex 会阻塞逻辑,需处理窗口后继续执行。
    • DisplayProgressBar 不阻塞逻辑,但要配合 ClearProgressBar 使用。

11.AssetDatabase

方法 描述 示例代码
AssetDatabase.CreateAsset(资源, 路径) 在指定路径创建资源,路径从 Assets/ 开始,不能在 StreamingAssets 中创建,不能创建预设体,资源为要创建的资源对象,路径需包含后缀 Material mat = new Material(Shader.Find("Specular")); AssetDatabase.CreateAsset(mat, "Assets/Resources/MyMaterial.mat");
AssetDatabase.CreateFolder(父文件夹, 新文件夹名) 在指定父文件夹下创建新文件夹,路径从 Assets/ 开始,父文件夹为父文件夹路径,新文件夹名为要创建的文件夹名称 AssetDatabase.CreateFolder("Assets/Resources", "MyTestFolder");
AssetDatabase.CopyAsset(源资源, 目标路径) 拷贝资源到指定目标路径,路径从 Assets/ 开始,需写后缀名,源资源为源资源的路径,目标路径为目标资源的保存路径 AssetDatabase.CopyAsset("Assets/Editor Default Resources/head.png", "Assets/Resources/MyTestFolder/head.png");
AssetDatabase.MoveAsset(老路径, 新路径) 将资源从老路径移动到新路径,路径从 Assets/ 开始,老路径为资源原来的路径,新路径为资源要移动到的路径 AssetDatabase.MoveAsset("Assets/Resources/MyTestFolder/head.png", "Assets/Resources/head.png");
AssetDatabase.DeleteAsset(资源路径) 删除指定路径的资源,路径从 Assets/ 开始,资源路径为要删除的资源的路径 AssetDatabase.DeleteAsset("Assets/Resources/head.png");
AssetDatabase.DeleteAssets(路径数组, 失败路径列表) 批量删除资源,路径从 Assets/ 开始,路径数组为要删除的资源路径数组,失败路径列表用于存储删除失败的路径列表 List failList = new List(); AssetDatabase.DeleteAssets(new string[] { "Assets/Resources/head.png", "Assets/Resources/head2.png" }, failList);
AssetDatabase.GetAssetPath(资源) 获取指定资源的路径,可配合 Selection 选中资源使用,资源为要获取路径的资源对象 Debug.Log(AssetDatabase.GetAssetPath(Selection.activeObject));
AssetDatabase.LoadAssetAtPath<资源类型>(资源路径) 根据指定路径加载资源,路径从 Assets/ 开始,仅在编辑器下使用,资源路径为要加载的资源的路径 Texture txt = AssetDatabase.LoadAssetAtPath("Assets/Resources/head.png");
AssetDatabase.Refresh() 对资源进行移动、导入、删除等操作后,执行刷新操作,以便在 Project 窗口中正确显示 AssetDatabase.Refresh();
AssetDatabase.GetImplicitAssetBundleName(资源路径) 返回指定资源所属的 AB 包名,路径从 Assets/ 开始,资源路径为要查询的资源的路径 string abName = AssetDatabase.GetImplicitAssetBundleName("Assets/Resources/head.png");

12.PrefabUtility

方法 描述 示例代码
PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径) 动态创建预设体,路径从 Assets/ 开始,需包含 .prefab 后缀,GameObject对象为要保存为预制体的游戏对象 GameObject go = new GameObject(); PrefabUtility.SaveAsPrefabAsset(go, "Assets/MyPrefab.prefab");
PrefabUtility.LoadPrefabContents(路径) 加载预制体到内存,路径从 Assets/ 开始,加载的预制体可用于修改,需与 UnloadPrefabContents 配对使用 GameObject prefab = PrefabUtility.LoadPrefabContents("Assets/MyPrefab.prefab");
PrefabUtility.UnloadPrefabContents(GameObject对象) 释放通过 LoadPrefabContents 加载到内存中的预制体,GameObject对象为要释放的预制体对象 PrefabUtility.UnloadPrefabContents(prefab);(假设 prefab 已加载)
PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功) 修改并保存已有预设体,预设体对象为要修改保存的预制体,是否保存成功为输出参数,用于指示保存操作是否成功 GameObject prefab = AssetDatabase.LoadAssetAtPath("Assets/MyPrefab.prefab"); bool success; PrefabUtility.SavePrefabAsset(prefab, out success);
PrefabUtility.InstantiatePrefab(Object对象) 实例化预设体,Object对象为要实例化的预制体对象 GameObject prefab = AssetDatabase.LoadAssetAtPath("Assets/MyPrefab.prefab"); PrefabUtility.InstantiatePrefab(prefab);

13.EditorApplication

方法 描述 示例代码
EditorApplication.update 每帧更新事件,可在编辑器执行逻辑,需添加和移除回调 EditorApplication.update += () => { if (EditorApplication.isPlaying) Debug.Log("播放中"); };
EditorApplication.hierarchyChanged 层级视图变化时触发,需添加和移除回调 EditorApplication.hierarchyChanged += () => Debug.Log("层级视图改变");
EditorApplication.projectChanged 项目资源变化时触发,需添加和移除回调 EditorApplication.projectChanged += () => Debug.Log("项目资源改变");
EditorApplication.playModeStateChanged 编辑器播放状态改变时触发,需添加和移除回调 EditorApplication.playModeStateChanged += () => Debug.Log("播放状态改变");
EditorApplication.pauseStateChanged 编辑器暂停状态改变时触发,需添加和移除回调 EditorApplication.pauseStateChanged += () => Debug.Log("暂停状态改变");
EditorApplication.applicationContentsPath 获取 Unity 安装目录 Data 路径 Debug.Log(EditorApplication.applicationContentsPath);
EditorApplication.applicationPath 获取 Unity 安装目录可执行程序路径 Debug.Log(EditorApplication.applicationPath);
EditorApplication.EnterPlaymode() 使编辑器进入播放模式 EditorApplication.EnterPlaymode();
EditorApplication.ExitPlaymode() 使编辑器退出播放模式 EditorApplication.ExitPlaymode();

14.CompilationPipeline

CompilationPipeline是Unity编辑器中的一个公共类,主要用于处理与代码编译相关的操作和事件。最常用的功能是判断代码是否编译结束,例如在动态生成脚本的情况下,只有在编译结束后才能使用新脚本。

创建自定义面板代码

using UnityEditor;

public class MyCompilationPipelineLearnWindow : EditorWindow
{
    [MenuItem("编辑器拓展教程/MyCompilationPipelineLearnWindow")]
    private static void OpenLesson46()
    {
        MyCompilationPipelineLearnWindow win =
            EditorWindow.GetWindow<MyCompilationPipelineLearnWindow>("CompilationPipeline知识点学习");
        win.Show();
    }
}

常用内容
在继承EditorWindow的类中,通过以下方式监听编译相关事件:

private void OnEnable()
{
    // 当一个程序集编译结束会主动调用该回调函数
    // 传入参数:string arg1(编译完成的程序集名)、CompilerMessage[] arg2(编译完成后产生的编译消息数组,包括编译警告和错误信息)
    CompilationPipeline.assemblyCompilationFinished += CompilationPipeline_assemblyCompilationFinished;

    // 当所有程序集编译结束会主动调用该回调函数
    // 传入参数:object obj(ActiveBuildStatus 活动生成状态对象)
    CompilationPipeline.compilationFinished += CompilationPipeline_compilationFinished;
}

private void CompilationPipeline_compilationFinished(object obj)
{
    Debug.Log("所有程序集编译结束");
}

private void CompilationPipeline_assemblyCompilationFinished(string arg1, CompilerMessage[] arg2)
{
    Debug.Log("程序集名:" + arg1);  
}

private void OnDestroy()
{
    CompilationPipeline.assemblyCompilationFinished -= CompilationPipeline_assemblyCompilationFinished;
    CompilationPipeline.compilationFinished -= CompilationPipeline_compilationFinished;
}

注意事项

  1. 对于CompilationPipelineassemblyCompilationFinishedcompilationFinished这两个事件,在添加回调函数后,要记得在合适的时机(比如脚本销毁时)移除回调函数,避免出现内存泄漏以及不必要的逻辑执行问题。
  2. CompilationPipeline类的这些功能仅在Unity编辑器环境中有效,在游戏打包后的运行环境中无法使用。

15.AssetImporter和AssetPostprocessor

AssetImporterAssetPostprocessor需配合使用,主要用于资源导入批量设置和资源导入后处理。

15.1.AssetPostprocessor

AssetPostprocessor(资源后处理器类)用于处理资源导入时的通用逻辑。可通过继承该类并实现回调方法自定义处理资源,常进行某种类型资源的通用设置和统一批量处理。

常用属性

  • AssetImporter assetImporter:对应类型的资源导入器对象
  • string assetPath:导入资源的路径

常用回调方法

  • 纹理相关
    • OnPreprocessTexture():导入纹理资源前调用,可修改导入设置
    • OnPostprocessTexture(Texture2D texture):导入纹理资源后调用,可进行后处理
  • 模型相关
    • OnPreprocessModel():导入模型资源前调用,可修改导入设置
    • OnPostprocessModel(GameObject obj):导入模型资源后调用,可进行后处理
  • 音频相关
    • OnPreprocessAudio():导入音频资源前调用,可修改导入设置
    • OnPostprocessAudio(AudioClip clip):导入音频资源后调用,可进行后处理

15.2.AssetImporter

AssetImporter(资源导入器类)是特定资源类型的资源导入程序的基类,提供配置和管理资源导入设置的方法和属性。一般使用其子类设置导入资源的相关信息。

子类

  • TextureImporter:用于导入纹理资源并配置设置
  • ModelImporter:用于导入模型资源并配置设置
  • AudioImporter:用于导入音频资源并配置设置
  • VideoClipImporter:用于导入视频资源并配置设置
  • ScriptedImporter:用于创建自定义资源导入器

联动使用示例

public class MyAssetPostprocessor : AssetPostprocessor
{
    // 纹理相关
    void OnPreprocessTexture()
    {
        Debug.Log("纹理设置回调" + assetPath);
        TextureImporter improter = assetImporter as TextureImporter;
        improter.textureType = TextureImporterType.Sprite;
        improter.mipmapEnabled = false;
    }

    void OnPostprocessTexture(Texture2D texture)
    {
        Debug.Log("纹理后处理回调" + texture.name);
        EditorUtility.CompressTexture(texture, TextureFormat.ETC_RGB4, TextureCompressionQuality.Fast);
    }

    // 模型相关
    void OnPreprocessModel()
    {
        ModelImporter improter = assetImporter as ModelImporter;
        // 可修改模型导入设置
    }

    void OnPostprocessModel(GameObject obj)
    {
        // 可进行模型后处理
    }

    // 音频相关
    void OnPreprocessAudio()
    {
        AudioImporter improter = assetImporter as AudioImporter;
        // 可修改音频导入设置
    }

    void OnPostprocessAudio(AudioClip clip)
    {
        // 可进行音频后处理
    }
}

你可能感兴趣的:(Unity知识快速回顾,unity,编辑器,游戏引擎)