Unity编辑器拓展(十一)-其他内容

AssetDatabase公共类、PrefabUtility公共类、EditorApplication公共类、CompilationPipeline公共类、AssetImporter和AssetPostprocessor

一、PrefabUtility公共类

1.1 PrefabUtility公共类是什么

  • 它是 Unity 编辑器中的一个公共类,提供了一些用于处理 Prefab(预制体或称预设体)的方法

  • 主要功能包括 实例化预制体、创建预制体、修改预制体 等等

  • 只要你有对预制体操作的相关需求,它可以在编辑器开发的任何地方对其进行使用

1.2 创建自定义面板用于进行知识讲解

1.3 常用API

1.3.1 动态创建预设体

  • 路径从Assets/…开始
1
PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径);

1.3.2 加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)

  • 路径从Assets/…开始
  • 这里的加载 本质上其实已经把预设体进行了实例化了 只不过该实例化对象并不是在传统的Scene窗口中(是在一个看不见的独立的场景中)
  • 注意:这下面代码中的两个方法需要配对使用,加载了就要卸载
1
2
3
PrefabUtility.LoadPrefabContents(路径)
// 释放加载的预设体对象
PrefabUtility.UnloadPrefabContents(GameObject对象)

1.3.3 修改已有预设体

  • 可以配合AssetDatabase.LoadAssetAtPath使用
1
PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功);

1.3.4 实例化预设体

1
PrefabUtility.InstantiatePrefab(Object对象)

1.4 更多内容

https://docs.unity3d.com/2022.3/Documentation/ScriptReference/PrefabUtility.html

1.5 代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
private void OnGUI()
{
//1.动态创建预设体 路径从Assets/...开始
// PrefabUtility.SaveAsPrefabAsset(GameObject对象, 路径);
if(GUILayout.Button("动态创建预设体"))
{
GameObject obj = new GameObject();
obj.AddComponent<Rigidbody>();
obj.AddComponent<BoxCollider>();
PrefabUtility.SaveAsPrefabAsset(obj, "Assets/Resources/TestObj.prefab");
DestroyImmediate(obj);
}

//2.加载预制体对象(不能用于创建,一般用于修改,会把预设体加载到内存中)
// 路径从Assets/...开始
// PrefabUtility.LoadPrefabContents(路径)
// 释放加载的预设体对象
// PrefabUtility.UnloadPrefabContents(GameObject对象)
// 注意:这两个方法需要配对使用,加载了就要释放

//这里的加载 本质上其实已经把预设体进行了实例化了 只不过该实例化对象并不是在传统的Scene窗口中(是在一个看不见的独立的场景中)
if (GUILayout.Button("加载预制体对象"))
{
//加载 到内存中 不能用来实例化 一般加载出来是进行修改的
GameObject testObj = PrefabUtility.LoadPrefabContents("Assets/Resources/TestObj.prefab");
testObj.AddComponent<MeshRenderer>();
//这种加载方式 是可以进行脚本移除 子对象创建的
DestroyImmediate(testObj.GetComponent<MeshRenderer>());
GameObject obj = new GameObject("新建子对象");
obj.transform.parent = testObj.transform;
PrefabUtility.SaveAsPrefabAsset(testObj, "Assets/Resources/TestObj.prefab");
//释放 一定要配合使用
PrefabUtility.UnloadPrefabContents(testObj);
}

//3.修改已有预设体
// PrefabUtility.SavePrefabAsset(预设体对象, out bool 是否保存成功);
// 可以配合AssetDatabase.LoadAssetAtPath使用
if (GUILayout.Button("修改已有预设体 "))
{
GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
testObj.AddComponent<BoxCollider>();
//这个方法不能存储实例化后的内容 只能存储对应的预设体对象
PrefabUtility.SavePrefabAsset(testObj);
}

//4.实例化预设体
// PrefabUtility.InstantiatePrefab(Object对象)
if (GUILayout.Button("实例化预设体"))
{
GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
PrefabUtility.InstantiatePrefab(testObj);

}
}

二、EditorApplication公共类

2.1 EditorApplication公共类是用来干什么的?

  • 它是 Unity 编辑器中的一个公共类,它主要提供了一些和编辑器本身相关的一些功能
  • 比如 编辑器事件监听(播放、暂停等)、生命周期判断(是否运行中、暂停中、编译中)
  • 编辑器进入播放模式、退出播放模式 等等功能

2.2 创建自定义面板用于进行知识理解

1
2
3
4
5
6
[MenuItem("Unity编辑器拓展/CompilationPipeline")]
private static void OpenWnd()
{
Lesson46 win = EditorWindow.GetWindow<Lesson46>("CompilationPipeline");
win.Show();
}

2.3 常用API

2.3.1 监听编辑器事件

  • EditorApplication.update:每帧更新事件,可以用于在编辑器中执行一些逻辑
  • EditorApplication.hierarchyChanged:层级视图变化事件,当场景中的对象发生变化时触发
  • EditorApplication.projectChanged:项目变化事件,当项目中的资源发生变化时触发
  • EditorApplication.playModeStateChanged:编辑器播放状态变化时触发
  • EditorApplication.pauseStateChanged:编辑器暂停状态变化时触发

2.3.2 管理编辑器生命周期相关

  • EditorApplication.isPlaying:判断当前是否处于游戏运行状态。
  • EditorApplication.isPaused:判断当前游戏是否处于暂停状态。
  • EditorApplication.isCompiling:判断Unity编辑器是否正在编译代码
  • EditorApplication.isUpdating:判断Unity编辑器是否正在刷新AssetDatabase

2.3.3 获取Unity应用程序路径相关

  • EditorApplication.applicationContentsPath:Unity安装目录Data路径
  • EditorApplication.applicationPath:Unity安装目录可执行程序路径

2.3.4 常用方法

  • EditorApplication.Exit(0):退出Unity编辑器
  • EditorApplication.ExitPlaymode():退出播放模式,切换到编辑模式
  • EditorApplication.EnterPlaymode():进入播放模式

2.4 更多内容

2.5 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
private void OnEnable()
{
EditorApplication.update += MyUpdate;
}

private void OnDestroy()
{
EditorApplication.update -= MyUpdate;
}

private void OnGUI()
{
if(GUILayout.Button("打印路径"))
{
Debug.Log(EditorApplication.applicationContentsPath);
Debug.Log(EditorApplication.applicationPath);
}

if (GUILayout.Button("播放"))
{
EditorApplication.EnterPlaymode();
}

if (GUILayout.Button("停止播放"))
{
EditorApplication.ExitPlaymode();
}
}


// Update is called once per frame
void MyUpdate()
{
if(EditorApplication.isPlaying)
{
Debug.Log("处于运行播放状态");
}
}

三、CompilationPipeline公共类

3.1 CompilationPipeline公共类是用来做什么的

  • 它是 Unity 编辑器中的一个公共类,用于处理代码编译相关的操作和事件的
  • 对于我们来说,我们最常用的是利用它得知代码是否编译结束,比如动态生成脚本时,我们需要在编译结束后才能使用新的脚本

3.2 依旧创建自定义面板用于进行知识理解

3.3 常用内容

3.3.1 CompilationPipeline.assemblyCompilationFinished

  • 命名空间:UnityEditor.Compilation;
  • 主要作用:当一个程序集编译结束会主动调用该回调函数
  • 传入的两个参数分别是
  • string arg1 : 编译完成的程序集名
  • CompilerMessage[] arg2 : 编译完成后产生的编译消息数组,包括编译警告和错误信息

3.3.2 CompilationPipeline.compilationFinished

  • 命名空间:UnityEditor.Compilation;
  • 主要作用:当所有程序集编译结束会主动调用该回调函数
  • 参数
  • object obj: ActiveBuildStatus 活动生成状态对象

3.4 更多内容

https://docs.unity3d.com/ScriptReference/Compilation.CompilationPipeline.html

3.5 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private void OnEnable()
{
CompilationPipeline.assemblyCompilationFinished += CompilationPipeline_assemblyCompilationFinished;
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;
}

3.6 部分效果

四、AssetImporter和AssetPostprocessor

4.1 知识点和什么有关

  • AssetImporter和AssetPostprocessor是需要配合进行使用的
  • 它们主要是用于处理
    • 1.资源导入批量设置(对导入的资源进行统一设置)
    • 2.资源导入后处理(对导入的资源进行统一的预处理)

4.2 AssetPostprocessor的作用

  • AssetPostprocessor(资源后处理器类)
  • 它主要用于处理资源导入时的通用逻辑
  • 可以通过继承该类,并实现其中的一些回调方法来自定义处理资源,一般会进行以下处理:
    • 1.进行某种类型资源的通用设置
    • 2.对某种类型资源进行统一批量的处理

4.2.1 继承它后的常用属性:

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

4.2.2 继承它后的常用回调方法有:

4.2.2.1 纹理相关

1
2
3
4
//  导入纹理资源之前调用,允许修改纹理的导入设置
void OnPreprocessTexture()
// 导入纹理资源之后调用,允许你对导入后为其进行后处理,比如 修改纹理格式、尺寸、压缩等等
void OnPostprocessTexture(Texture2D texture)

4.2.2.2 模型相关

1
2
3
4
//  导入模型资源之前调用,允许修改纹理的导入设置
void OnPreprocessModel()
// 导入模型资源之后调用,允许你对导入后为其进行后处理,比如 修改网格、材质、动画等
void OnPostprocessModel(GameObject obj)

4.2.2.3 音频相关

1
2
3
4
//  导入音频资源之前调用,允许修改音频的导入设置
void OnPreprocessAudio()
// 导入音频资源之后调用,允许你对导入后为其进行后处理,比如 修改音频格式、质量等
void OnPostprocessAudio(AudioClip clip)
//等等等等

4.2.3 更多内容

https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html

  • 注意:如果只想对某种资源中的某些内容进行处理,可以自己加命名规则

4.3 AssetImporter的作用

  • AssetImporter(资源导入器 类)
  • 它是 特定资源类型的资源导入程序的基类
  • 它提供了一些方法和属性,用于配置和管理资源的导入设置
  • 一般我们不会直接使用该类,而是通过使用继承它的子类来设置导入资源的相关信息
  • 当我们导入一个资源时,在Inspector窗口中进行的相关设置,都是通过继承该类的子类实现的

4.3.1 它的子类一般按照资源类型来划分

4.4 代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
//纹理相关
// 导入纹理资源之前调用,允许修改纹理的导入设置
void OnPreprocessTexture()
{
//1.资源导入批量设置(对导入的资源进行统一设置)
Debug.Log("纹理设置回调" + assetPath);

TextureImporter improter = assetImporter as TextureImporter;
improter.textureType = TextureImporterType.Sprite;
improter.mipmapEnabled = false;

}
// 导入纹理资源之后调用,允许你对导入后为其进行后处理,比如 修改纹理格式、尺寸、压缩等等
void OnPostprocessTexture(Texture2D texture)
{
//2.资源导入后处理(对导入的资源进行统一的预处理)
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)
{

}

4.5 注意

脚本需继承AssetPostprocessor

4.6效果

右边显示有对应的脚本处理导入设置