2024-06-10 Unity 编辑器开发之编辑器拓展10 —— 其他常见工具类

1 AssetDatabase

​ AssetDatabase 是 Unity 引擎中的一个编辑器类,用于在编辑器环境中管理和操作项目中的资源(Assets)。

​ 它提供一系列静态方法,使得开发者能够在编辑器脚本中进行资源的创建、拷贝、移动、删除等操作。

​ 在编辑器相关处都可以使用 AssetDatabase,但它属于编辑器功能,无法被打包出去,只能在 Unity 编辑器中使用。

1.1 准备工作

​ AssetDatabase 可以在任何编辑器功能开发时使用,但为了讲解方便,这里通过一个自定义窗口来进行讲解。

using UnityEditor;
using UnityEngine;

public class Lesson42Window : EditorWindow
{
    [MenuItem("Unity 编辑器拓展/Lesson42/AssetDatabase 知识讲解")]
    public static void Open() {
        Lesson42Window win = GetWindow<Lesson42Window>();
        win.Show();
    }

    private void OnGUI() { }
}

1.2 常用 API

  1. 创建资源
public static extern void CreateAsset(UnityEngine.Object asset, string path);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("创建资源")) {
        var mat = new Material(Shader.Find("Legacy Shaders/Specular"));
        AssetDatabase.CreateAsset(mat, "Assets/Resources/MyMaterial.mat");
    }
}
  • 路径从 Assets/… 开始,且文件夹必须存在。
  • 不能在 StreamingAssets 中创建资源。
  • 不能创建预设体(需使用 PrefabUtility 创建)。
  • 只能创建资源相关,例如材质球等。
  • 路径需要写后缀。
  1. 创建文件夹
public static extern string CreateFolder(string parentFolder, string newFolderName);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("创建文件夹")) {
        AssetDatabase.CreateFolder("Assets/Resources", "MyFolder");
    }
}
  • 路径从 Assets/… 开始。
  • 路径需要写后缀。
  1. 拷贝资源
public static extern bool CopyAsset(string path, string newPath);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("拷贝资源")) {
        AssetDatabase.CopyAsset("Assets/Resources/MyMaterial.mat", "Assets/Resources/newMaterial.mat");
    }
}
  • 路径从 Assets/… 开始。
  • 路径需要写后缀。
  1. 移动资源
public static extern bool DeleteAsset(string path);
public static bool DeleteAssets(string[] paths, List<string> outFailedPaths);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("删除资源")) {
        AssetDatabase.DeleteAsset("Assets/Resources/newMaterial2.mat");
    }
}
  • 路径从 Assets/… 开始。
  • 路径需要写后缀。
  • 目标资源不存在不会报错。
  1. 获取资源路径
public static extern string GetAssetPath(UnityEngine.Object assetObject);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("获取资源路径")) {
        Debug.Log(AssetDatabase.GetAssetPath(Selection.activeObject));
    }
}
  • 可以配合 Selection 选中资源一起使用。
  1. 加载资源
public static T LoadAssetAtPath<T>(string assetPath) where T : UnityEngine.Object;
public static extern UnityEngine.Object[] LoadAllAssetsAtPath(string assetPath);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("加载资源")) {
        var mat = AssetDatabase.LoadAssetAtPath<Material>("Assets/Resources/newMaterial.mat");
        Debug.Log(mat.name);
    }
}
  • 路径从 Assets/… 开始。

  • 路径需要写后缀。

  • LoadAllAssetsAtPath 一般可以用来加载图集资源,返回值为 Object 数据。

    如果是图集,第一个为图集本身,之后的便是图集中的所有 Sprite。

  1. 刷新
public static void Refresh();
  • AssetDatabase 的 API 内部会自动调用刷新。使用其他操作时需要手动刷新。
  1. 获取资源 AB 包名称
public static extern string GetImplicitAssetBundleName(string assetPath);
  • 路径从 Assets/… 开始。

更多内容:https://docs.unity3d.com/ScriptReference/AssetDatabase.html

2 PrefabUtility

​ PrefabUtility 是 Unity 编辑器中的一个公共类,提供一些用于处理 Prefab(预制体或称预设体)的方法。
​ 主要功能包括:实例化预制体、创建预制体、修改预制体等等。

1 准备工作

using UnityEditor;
using UnityEngine;

public class Lesson44Window : EditorWindow
{
    [MenuItem("Unity 编辑器拓展/Lesson44/PrefabUtility 知识讲解")]
    public static void Open() {
        Lesson44Window win = GetWindow<Lesson44Window>();
        win.Show();
    }

    private void OnGUI() { }
}

2 常用 API

  1. 创建预设体
public static GameObject SaveAsPrefabAsset(GameObject instanceRoot, string assetPath);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("动态创建预设体")) {
        GameObject obj = new GameObject();
        obj.AddComponent<Rigidbody>();
        obj.AddComponent<BoxCollider>();
        PrefabUtility.SaveAsPrefabAsset(obj, "Assets/Resources/TestObj.prefab");
        DestroyImmediate(obj); // 立即删除 obj
    }
}
  1. 加载预制体
public static GameObject LoadPrefabContents(string assetPath);
public static void UnloadPrefabContents(GameObject contentsRoot);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("加载预制体对象")) {
        GameObject testObj = PrefabUtility.LoadPrefabContents("Assets/Resources/TestObj.prefab");
        testObj.AddComponent<MeshRenderer>();
        PrefabUtility.SaveAsPrefabAsset(testObj, "Assets/Resources/TestObj.prefab"); // 需要新建预制体保存
        PrefabUtility.UnloadPrefabContents(testObj);
    }
}
  • 加载到内存中,不能用来实例化,一般加载出来进行修改。
  • 该方法的加载其实已经实例化了预设体,但该实例化对象并在 Scene 窗口中,而是在一个看不见的独立的场景中。
  • 可以进行脚本移除,子对象创建等操作。
  • 两个方法需要配对使用,加载了就要释放。
  1. 修改预设体
public static GameObject SavePrefabAsset(GameObject asset);
public static GameObject SavePrefabAsset(GameObject asset, out bool savedSuccessfully);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("修改已有预设体")) {
        GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
        testObj.AddComponent<BoxCollider>();
        PrefabUtility.SavePrefabAsset(testObj);
    }
}
  • 该方法不能存储实例化后的内容,只能存储对应的预设体对象。
  1. 实例化预制体
public static UnityEngine.Object InstantiatePrefab(UnityEngine.Object assetComponentOrGameObject);

// 示例:
private void OnGUI() {
    if (GUILayout.Button("实例化预设体")) {
        GameObject testObj = AssetDatabase.LoadAssetAtPath<GameObject>("Assets/Resources/TestObj.prefab");
        PrefabUtility.InstantiatePrefab(testObj);
    }
}

更多内容:https://docs.unity3d.com/2022.3/Documentation/ScriptReference/PrefabUtility.html

3 EditorApplication

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

3.1 准备工作

using UnityEditor;
using UnityEngine;

public class Lesson45Window : EditorWindow
{
    [MenuItem("Unity 编辑器拓展/Lesson45/EditorApplication 知识讲解")]
    public static void Open() {
        Lesson45Window win = GetWindow<Lesson45Window>();
        win.Show();
    }

    private void OnEnable() {
        // 添加监听事件
        EditorApplication.update += ...;
    }

    private void OnDestroy() {
        // 移除监听事件
        EditorApplication.update -= ...;
    }
}

3.2 常用 API

  1. 监听编辑器事件

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

    • EditorApplication.isPlaying:判断当前是否处于游戏运行状态。
    • EditorApplication.isPaused:判断当前游戏是否处于暂停状态。
    • EditorApplication.isCompiling:判断 Unity 编辑器是否正在编译代码。
    • EditorApplication.isUpdating:判断 Unity 编辑器是否正在刷新 AssetDatabase。
  3. 获取 Unity 应用程序路径相关

    • EditorApplication.applicationContentsPath:Unity 安装目录 Data 路径。
    • EditorApplication.applicationPath:Unity 安装目录可执行程序路径。
  4. 常用方法

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

更多内容:

4 CompilationPipeline

​ CompilationPipeline 是 Unity 编辑器中的一个公共类,用于处理代码编译相关的操作和事件,通常使用它得知代码是否编译结束。

​ 比如动态生成脚本时,需要在编译结束后才能使用新的脚本。

4.1 CompilationPipeline.assemblyCompilationFinished

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

4.2 CompilationPipeline.compilationFinished

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

4.3 示例

using UnityEditor;
using UnityEditor.Compilation;
using UnityEngine;

public class Lesson46Window : EditorWindow
{
    [MenuItem("Unity 编辑器拓展/Lesson46/CompilationPipeline 知识讲解")]
    public static void Open() {
        Lesson46Window win = GetWindow<Lesson46Window>();
        win.Show();
    }

    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;
    }
}

更多内容:https://docs.unity3d.com/ScriptReference/Compilation.CompilationPipeline.html

5 AssetPostprocessor

​ AssetPostprocessor(资源后处理器)主要用于处理资源导入时的通用逻辑,可以通过继承该类并实现其中的一些回调方法来自定义处理资源。

​ 一般会进行以下处理:

  1. 进行某种类型资源的通用设置。
  2. 对某种类型资源进行统一批量的处理。

5.1 常用 API

  1. 常用属性:

    • AssetImporter assetImporter:对应类型的资源导入器对象。
    • string assetPath:导入资源的路径。
  2. 常用回调方法:

    • void OnPreprocessTexture():导入纹理资源之前调用,允许修改纹理的导入设置。
    • void OnPostprocessTexture(Texture2D texture):导入纹理资源之后调用,允许对导入后为其进行后处理,例如修改纹理格式、尺寸、压缩等等。
    • void OnPreprocessModel():导入模型资源之前调用,允许修改纹理的导入设置。
    • void OnPostprocessModel(GameObject obj):导入模型资源之后调用,允许对导入后为其进行后处理,例如修改网格、材质、动画等。
    • void OnPreprocessAudio():导入音频资源之前调用,允许修改纹理的导入设置。
    • void OnPostprocessAudio(AudioClip clip):导入音频资源之后调用,允许对导入后为其进行后处理,例如修改音频格式、质量等。
    • 等等

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

更多内容:https://docs.unity3d.com/ScriptReference/AssetPostprocessor.html

5.2 示例

using UnityEditor;
using UnityEngine;

public class Lesson47 : AssetPostprocessor
{
    void OnPreprocessTexture() { }

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

    void OnPreprocessModel() { }

    void OnPostprocessModel(GameObject obj) { }

    void OnPreprocessAudio() { }

    void OnPostprocessAudio(AudioClip clip) { }
}

6 AssetImporter

​ AssetImporter(资源导入器)是特定资源类型的资源导入程序的基类,用于配置和管理资源的导入设置。

​ 一般不会直接使用该类,而是通过使用继承它的子类来设置导入资源的相关信息。

​ 当我们导入一个资源时,在 Inspector 窗口中进行的相关设置都是通过继承该类的子类实现的。

分类:

  1. TextureImporter:纹理导入器。
  2. ModelImporter:模型导入器。
  3. AudioImporter:音频导入器。
  4. VideoClipImporter:视频导入器。
  5. ScriptedImporter:自定义的资源导入器,对特定格式的资源进行自定义配置处理。

​ 使用示例:

using UnityEditor;
using UnityEngine;

public class Lesson47 : AssetPostprocessor
{
    void OnPreprocessTexture() {
        Debug.Log("纹理设置回调" + assetPath);

        // 进行导入设置
        TextureImporter importer = (TextureImporter) assetImporter; // TextureImporter
        importer.textureType   = TextureImporterType.Sprite;
        importer.mipmapEnabled = false;
    }

    void OnPostprocessTexture(Texture2D texture) { }

    void OnPreprocessModel() {
        TextureImporter importer = (ModelImporter) assetImporter; // ModelImporter
    }

    void OnPostprocessModel(GameObject obj) { }

    void OnPreprocessAudio() {
        TextureImporter importer = (AudioImporter) assetImporter; // AudioImporter
    }

    void OnPostprocessAudio(AudioClip clip) { }
}

更多内容:

最近更新

  1. TCP协议是安全的吗?

    2024-06-10 17:04:02       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-06-10 17:04:02       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-06-10 17:04:02       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-06-10 17:04:02       18 阅读

热门阅读

  1. Leetcode 3181. Maximum Total Reward Using Operations II

    2024-06-10 17:04:02       9 阅读
  2. 机器学习:如何在Python中实现决策树分类?

    2024-06-10 17:04:02       10 阅读
  3. 为什么考试总是无法发挥正常水平?

    2024-06-10 17:04:02       8 阅读
  4. 2D图片的描边

    2024-06-10 17:04:02       10 阅读
  5. 使用vue3+ts封装一个Switch开关组件

    2024-06-10 17:04:02       10 阅读
  6. 每个寒暑假学习一项新技能

    2024-06-10 17:04:02       11 阅读
  7. python小tips

    2024-06-10 17:04:02       8 阅读
  8. git命令

    git命令

    2024-06-10 17:04:02      8 阅读
  9. Python之Pandas详解

    2024-06-10 17:04:02       9 阅读