当前位置: 首页 > news >正文

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<Lesson03_自定义窗口拓展>();
GetWindow创建单例唯一的窗口对象。Lesson03_自定义窗口拓展 singletonWindow = EditorWindow.GetWindow<Lesson03_自定义窗口拓展>();
GetWindowWithRect返回一个指定位置、大小的窗口。Rect rect = new Rect(100, 100, 200, 200); Lesson03_自定义窗口拓展 sizedWindow = EditorWindow.GetWindowWithRect<Lesson03_自定义窗口拓展>(rect);
HasOpenInstances检查编辑器窗口是否打开。bool isOpen = EditorWindow.HasOpenInstances<Lesson03_自定义窗口拓展>();

成员变量

成员变量描述示例代码
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<Lesson03_自定义窗口拓展>();
GetWindow创建单例唯一的窗口对象Lesson03_自定义窗口拓展 singletonWindow = EditorWindow.GetWindow<Lesson03_自定义窗口拓展>();
GetWindowWithRect返回指定位置、大小的窗口Rect rect = new Rect(100, 100, 200, 200); Lesson03_自定义窗口拓展 sizedWindow = EditorWindow.GetWindowWithRect<Lesson03_自定义窗口拓展>(rect);
HasOpenInstances检查编辑器窗口是否打开bool isOpen = EditorWindow.HasOpenInstances<Lesson03_自定义窗口拓展>();

成员变量

变量名描述示例代码
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)根据指定路径加载资源,路径需包含后缀名。资源不存在时返回nullvar 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<T>(UnityEngine.Object obj, bool allowSceneObjects, string filter, int controlID)显示对象选择器窗口。T为资源类型,obj为默认选中对象引用,allowSceneObjects决定是否允许选择场景对象,filter用于过滤对象名称,controlID一般设为0EditorGUIUtility.ShowObjectPicker<GameObject>(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;<br>if (Event.current.commandName == "ObjectSelectorUpdated"){ // 当选择发生更新时通知进入}<br>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<MyEditorWindow>(); 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获取当前在面板上选择的物体数组,未选择则返回 Nullvar 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<GameObject>(SelectionMode.Unfiltered)获取所有选中的GameObject
  • 示例 2:使用Selection.GetFiltered<Texture2D>(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若为键盘事件,可获取对应的 KeyCodeif (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 视图中绘制 GUIHandles.BeginGUI();
Handles.EndGUI()结束在 Scene 视图中绘制 GUIHandles.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. 静态参数

静态参数描述
Handlescolor在调用 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. 静态参数

静态参数描述示例代码
Gizmoscolor修改 Gizmos 绘制图形的颜色Gizmos.color = Color.green;
Gizmosmatrix修改 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显示含确定按钮的提示窗口,阻塞逻辑boolif (EditorUtility.DisplayDialog("标题", "信息", "确定")) Debug.Log("点击确定");
EditorUtility.DisplayDialogComplex显示三按钮提示面板,阻塞逻辑intint res = EditorUtility.DisplayDialogComplex("标题", "信息", "按钮1", "按钮2", "按钮3");
EditorUtility.DisplayProgressBar显示进度条,不阻塞逻辑voidEditorUtility.DisplayProgressBar("进度条", "信息", 0.5f);
EditorUtility.ClearProgressBar关闭进度条voidEditorUtility.ClearProgressBar();
EditorUtility.SaveFilePanel显示文件存储面板stringstring path = EditorUtility.SaveFilePanel("标题", "", "文件名", "后缀");
EditorUtility.SaveFilePanelInProject显示项目内文件存储面板stringstring path = EditorUtility.SaveFilePanelInProject("标题", "文件名", "后缀", "摘要");
EditorUtility.SaveFolderPanel显示文件夹存储面板stringstring path = EditorUtility.SaveFolderPanel("标题", "", "默认名");
EditorUtility.OpenFilePanel显示打开文件面板stringstring path = EditorUtility.OpenFilePanel("标题", "", "后缀");
EditorUtility.OpenFolderPanel显示打开文件夹面板stringstring path = EditorUtility.OpenFolderPanel("标题", "", "默认名");
EditorUtility.CompressTexture压缩纹理到指定格式voidEditorUtility.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<string> failList = new List<string>(); 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<Texture>("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<GameObject>("Assets/MyPrefab.prefab"); bool success; PrefabUtility.SavePrefabAsset(prefab, out success);
PrefabUtility.InstantiatePrefab(Object对象)实例化预设体,Object对象为要实例化的预制体对象GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>("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)
    {
        // 可进行音频后处理
    }
}

相关文章:

  • Jackson使用ObjectNode对象实现JSON对象数据(一):增、删、改、查
  • springcloud是多个springboot项目分开的吗
  • CCF开源发展委员会常委会会议召开,共绘开源新蓝图
  • 怎样对比找到两个git仓库的差异
  • 不能将下载行为传输到IDM
  • 固定翼无人机姿态和自稳模式
  • 【语料数据爬虫】Python爬虫|批量采集讲话稿数据【范文网】(2)
  • Cocos Creator Shader入门实战(六):使用setProperty动态设置材质属性,以及材质常用接口
  • 微信小程序-通用印刷体识别cv/ocr/comm报media data missing hint错
  • 两个还算好用的ppt转word和PDF转word的python脚本
  • 执行adb指令报错:error: more than one device/emulator原因及解决方法
  • 构建高效的LinkedIn图像爬取工具
  • 如何解释storefile文件的合并和分裂?
  • 利用 Agent TARS 技术实现互联网舆情监测与事件自动化创建的可行性与前景
  • 内网(域)渗透测试流程和模拟测试day--1--信息收集阶段
  • DeiT:数据高效的图像Transformer及其工作原理详解
  • 【2025】基于springboot+vue的医院在线问诊系统设计与实现(源码、万字文档、图文修改、调试答疑)
  • 【详细解决】pycharm 终端出现报错:“Failed : 无法将“Failed”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。
  • python项目使用docker在linux系统离线部署
  • 关于网络的一点知识(持续更新)
  • 海关总署统计分析司司长:4月进出口增速较一季度加快4.3个百分点
  • 圆桌丨权威专家解读中俄关系:在新形势下共同应对挑战、共创发展机遇
  • 新疆生产建设兵团草湖项目区副主任宋全伟接受审查调查
  • 商务部新闻发言人就中美经贸高层会谈答记者问
  • 赵乐际:深入学习贯彻习近平生态文明思想,推动森林法全面有效贯彻实施
  • 秦洪看盘|涌现新逻辑,A股放量回升