UFL5-4——Editor资源加载模块

Editor资源加载模块

  1. Editor资源加载的主要作用

    当项目主要采用AssetBundle资源加载时,用于在开发时进行资源加载,方便资源管理,避免资源重复打包

  2. Editor资源加载的基本原理

    利用Unity编辑器拓展中的相关API来进行加载即可

    • ​AssetDatabase.LoadAssetAtPath()​
    • ​EditorGUIUtility.Load()​

Editor资源加载的主要作用

  1. 避免在开发时频繁的打AB包降低开发效率
  2. 方便资源管理,避免资源重复打包

在进行项目开发时,最终发布的项目一般为了达到以下两个目的

  1. 减小包体大小
  2. 热更新

最终会通过AssetBundle资源加载作为主要加载方式
那么也就是说最终我们发布项目时,几乎所有的的游戏资源都会在AB包中的
AB包最终会放置在 StreamingAssets 中 或者 远程资源服务器 中

但是在开发期间,如果进行频繁的资源打包(资源放入AssetBundle包),会大大降低我们的开发效率。

因此我们在开发功能时,可以不通过AB包加载资源,而是在最终要测试或发布时才把资源整合进AB包。
但是为了方便资源管理,我们也不能将资源放在Resources中来进行加载,因为最终Resources中的资源会被打包出去。

那么此时Editor资源加载的作用就体现出来了,我们可以将资源放进不会被打包的Editor文件夹中,
开发时通过Editor资源加载,测试和发布时使用AssetBundle资源加载。

image

Editor资源加载的基本原理

  1. 利用Unity编辑器拓展相关API:AssetDatabase.LoadAssetAtPath​
  2. 可以加载工程路径下指定位置资源:EditorGUIUtility.Load​
    可以加载工程路径下Editor Default Resource文件夹下资源,我们可以根据自己的需求,选择任意API进行使用

具体实现

主要使用的API

  1. ​AssetDatabase.LoadAssetAtPath()​,用于加载单个资源
  2. ​AssetDatabase.LoadAllAssetRepresentationsAtPath()​,用于加载图集资源中的内容(该API用于加载所有子资源)

注意:这两个API加载资源的路径都是从 Assets/...​ 开始

创建用于放置资源的文件夹

我们可以创建Editor文件夹,以后我们最终会打包为AB包的资源都放置在此处

image

实现Editor资源管理器

封装API,主要提供加载单个资源以及加载图集资源的API

  • LoadEditorRes<>​ 用于加载单个资源
  • LoadSprite​ 用于加载某个图集内的图片
  • LoadSprites​ 用于加载某个图集,返回键为图片名值为图片的包括所有图集内图片的字典

值得一提的是,由于AssetDatabase​相关API加载资源时,传入的路径参数都要包括后缀名,因此封装的API要根据传入的参数来判断使用什么后缀名

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
56
57
58
59
60
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using static TMPro.SpriteAssetUtilities.TexturePacker_JsonArray;

/// <summary>
/// 编辑器资源管理器,仅允许在开发时使用此管理器加载资源,发布后不可使用!
/// </summary>
public class EditorResManager : BaseManager<EditorResManager>
{
/// <summary>
/// 用于放置需要打包进AB包中资源路径
/// </summary>
private string rootPath = "Assets/Editor/ArtRes/";

private EditorResManager() { }

//加载单个资源的
public T LoadEditorRes<T>(string path) where T : Object
{
//预设体、纹理、材质球、音效
string suffixName = "";
if (typeof(T) == typeof(GameObject))
suffixName = ".prefab";
else if (typeof(T) == typeof(Material))
suffixName = ".mat";
else if (typeof(T) == typeof(Texture))
suffixName = ".png";
else if (typeof(T) == typeof(AudioClip))
suffixName = ".mp3";

T res = AssetDatabase.LoadAssetAtPath<T>(rootPath + path + suffixName);
return res;
}

//加载图集内某个图片
public Sprite LoadSprite(string path, string spriteName)
{
Object[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(rootPath + path + ".png");
foreach (var item in sprites)
{
if (spriteName == item.name)
return item as Sprite;
}
return null;
}

//加载图集文件中的所有子图片并返回给外部
public Dictionary<string, Sprite> LoadSprites(string path)
{
Dictionary<string, Sprite> spriteDic = new Dictionary<string, Sprite>();
Object[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(rootPath + path + ".png");
foreach (var item in sprites)
{
spriteDic.Add(item.name, item as Sprite);
}
return spriteDic;
}
}

使用示例

1
2
3
4
void Start()
{
Instantiate(EditorResManager.Instance.LoadEditorRes<GameObject>("Cube"));
}

输出:image

补充:让该脚本主要逻辑仅在编辑器环境下编译

由于该脚本在非Editor文件夹内调用了Editor相关的API,因此,在打包AB包的时候,这里的代码会报错,导致打包不成功

因此我们需要使用预处理器指令,配合UNITY_EDITER​来选择性编译,让该脚本的方法内的实现在非编辑器模式下不会被编译

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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

/// <summary>
/// 编辑器资源管理器,仅允许在开发时使用此管理器加载资源,发布后不可使用!
/// </summary>
public class EditorResManager : BaseManager<EditorResManager>
{
#if UNITY_EDITOR
/// <summary>
/// 用于放置需要打包进AB包中资源路径
/// </summary>
private string rootPath = "Assets/Editor/ArtRes/";
#endif

private EditorResManager() { }

//加载单个资源的
public T LoadEditorRes<T>(string path) where T : Object
{
#if UNITY_EDITOR
//预设体、纹理、材质球、音效
string suffixName = "";
if (typeof(T) == typeof(GameObject))
suffixName = ".prefab";
else if (typeof(T) == typeof(Material))
suffixName = ".mat";
else if (typeof(T) == typeof(Texture))
suffixName = ".png";
else if (typeof(T) == typeof(AudioClip))
suffixName = ".mp3";

T res = AssetDatabase.LoadAssetAtPath<T>(rootPath + path + suffixName);
return res;
#else
throw new System.Exception("不允许在非编辑器模式下调用该方法加载资源!");
#endif
}

//加载图集内某个图片
public Sprite LoadSprite(string path, string spriteName)
{
#if UNITY_EDITOR
Object[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(rootPath + path + ".png");
foreach (var item in sprites)
{
if (spriteName == item.name)
return item as Sprite;
}
return null;
#else
throw new System.Exception("不允许在非编辑器模式下调用该方法加载资源!");
#endif
}

//加载图集文件中的所有子图片并返回给外部
public Dictionary<string, Sprite> LoadSprites(string path)
{
#if UNITY_EDITOR
Dictionary<string, Sprite> spriteDic = new Dictionary<string, Sprite>();
Object[] sprites = AssetDatabase.LoadAllAssetRepresentationsAtPath(rootPath + path + ".png");
foreach (var item in sprites)
{
spriteDic.Add(item.name, item as Sprite);
}
return spriteDic;
#else
throw new System.Exception("不允许在非编辑器模式下调用该方法加载资源!");
#endif
}
}