Unity学习之资源管理(Resources、AssetDatabase、AssetBundle、Addressable)文章内置有链接可以供我们学习其他资源管理
(2) 管理资源方式,将资源组织到自己建立目录下比如下图GameRes目录,判断如果在编辑器模式下,通过AssetDatabase.LoadAsserAtPath加载资源,如果打包移动端这个方案不可以了,必须先打包assetbundle,两种方式,如果需要放在远端,放到指定远程资源服务器上。Addressable Assets是 Unity 推出的新一代资源管理系统,基于 AssetBundle
在 Unity 中,资源管理是游戏开发的核心环节之一。以下详细介绍四种常用的资源管理方式:Resources、AssetDatabase、AssetBundle 和 Addressable,并提供相应的代码案例。
1. Resources
Resources 是 Unity 最基础的资源管理方式,需要把资源文件放置在项目 的Assets/Resources目录下。若该目录不存在,可手动创建, 这个文件夹 下的资源将被加密和压缩打包。
Resources工作原理:
(1) 资源定位:Resource API在运行时会遍历Assets 目录及其子目录下名为“Resources”的文件夹,然后通过路径字符串进行资源定位(路径字符串是相对于Resources文件夹的相对路径,不包含文件拓展名。
(2) 资源打包:一旦找到匹配的资源文件,Resource API会将资源文件及其元数据打包到一个序列化文件中。这个序列化文件包含 了资源的实际数据以及其他描述信息,如资源类型、引用关系等。
(3) 资源加载:当资源被加载时,Resource API会读取序列化文件,将资源的实际数据加载到内存中。
缺点:
1. 所有 Resources 文件夹中的资源会被打包到游戏主包中, 这一限制,意味着Resource API并不支持打空包。
2. 如果是实战项目,建议将资源打成AssetBundle放在StreamingAssets目录或服务器中,方便热更资源。
Resource同步加载资源:
使用Resources.Load方法能够同步加载资源。该方法会阻塞主线程,直至资源加载完成。
using UnityEngine;
public class SyncResourceLoader : MonoBehaviour
{
void Start()
{
// 加载位于Resources目录下的预制体,"PrefabName"为预制体文件名(不含扩展名)
GameObject prefab = Resources.Load<GameObject>("PrefabName");
if (prefab != null)
{
// 实例化预制体
Instantiate(prefab);
}
}
// 加载 Prefabs 下所有 GameObject
GameObject[] arr = Resources.LoadAll<GameObject>("Prefabs");
}
Resource异步加载资源
使用Resources.LoadAsync方法可以异步加载资源,此方法不会阻塞主线程,在资源加载过程中,游戏可以继续运行。
using UnityEngine;
using System.Collections;
public class AsyncResourceLoader : MonoBehaviour
{
IEnumerator Start()
{
// 开始异步加载位于Resources目录下的预制体
ResourceRequest request = Resources.LoadAsync<GameObject>("PrefabName");
// 等待资源加载完成
yield return request;
if (request.asset != null)
{
GameObject prefab = request.asset as GameObject;
// 实例化预制体
Instantiate(prefab);
}
}
}
Resource卸载资源
当资源不再使用时,为避免内存泄漏,需要及时卸载资源。可以使用Resources.UnloadUnusedAssets方法卸载所有未使用的资源:
卸载资源(重点防内存泄漏)
csharp
运行
// 卸载单个资源
Resources.UnloadAsset(某资源);
// 卸载所有未使用资源
Resources.UnloadUnusedAssets();
// 卸载所有未使用的资源
Resources.UnloadUnusedAssets();
路径写法必记规则
- 路径不写 Resources,从子目录开始写
- 不带文件后缀(.png/.prefab/.mp3 都不要写)
- 分隔符用 */ 不能用 *
- 大小写编辑器不敏感,打包后移动端敏感建议统一小写、命名不要中文空格
2. AssetDatabase
AssetDatabase是UnityEditor资源管理类,它提供了在Unity的Assets目录及其子目录下查找、加载已有的资源,还允许用户创建、删除、修改资源。
与Resource相比优势:
(1) 灵活性和组织性:AssetDatabase提供了更灵活和组织性更强的资源管理方式。通过AssetDatabase,您可以在项目中自由地组织和管理资源文件的文件夹结构,以便更好地组织和定位资源。而Resource文件夹只提供了一个默认的资源文件夹(Assets/Resorces文件夹),资源文件的组织和管理相对较为有限。
(2) 运行时加载:使用AssetDatabase允许用户在运行时动态加载和卸载资源。用户可以根据需要按需加载资源,减少内存占用和加载时间。而使用Resource方式加载资源,资源文件需要事先打包到应用程序中,无法动态加载和卸载。
(3) 打空包:这是放弃使用Resource转而使用AssetDatabase最重要的原因。
注意点:
(1) AssetDatabase仅在Unity编辑器模式下使用,当构建游戏时请使用其他资源管理方案!!!
(2) 管理资源方式,将资源组织到自己建立目录下比如下图GameRes目录,判断如果在编辑器模式下,通过AssetDatabase.LoadAsserAtPath加载资源,如果打包移动端这个方案不可以了,必须先打包assetbundle,两种方式,如果需要放在远端,放到指定远程资源服务器上。放在本地将打包好的assetbundle移到StreamingAssets文件夹,通过AssetBundle.LoadFromFile加载资源。
AssetDataBase导入资源:
using UnityEngine;
using UnityEditor;
//Unity用脚本导入资源(没什么卵用)
public class ImportAsset
{
[MenuItem("AssetDatabase/ImportExample")]
static void ImportExample()
{
AssetDatabase.ImportAsset("Assets/UI/cube.png", ImportAssetOptions.Default);
}
}
AssetDataBase加载资源:
using UnityEditor;
using UnityEngine;
public class AssetDatabaseExample : EditorWindow
{
[MenuItem("Window/AssetDatabase Example")]
static void ShowWindow()
{
GetWindow<AssetDatabaseExample>("AssetDatabase Example");
}
void OnGUI()
{
if (GUILayout.Button("Load Asset"))
{
// 加载资源(需要完整路径)
Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>("Assets/Textures/Example.png");
if (texture != null)
{
Debug.Log("Loaded texture: " + texture.name);
}
}
if (GUILayout.Button("Find Assets"))
{
// 查找指定类型的所有资源
string[] guids = AssetDatabase.FindAssets("t:AudioClip");
foreach (string guid in guids)
{
string path = AssetDatabase.GUIDToAssetPath(guid);
Debug.Log("Found audio clip: " + path);
}
}
if (GUILayout.Button("Create Material"))
{
// 创建新资源
Material material = new Material(Shader.Find("Standard"));
AssetDatabase.CreateAsset(material, "Assets/Materials/NewMaterial.mat");
AssetDatabase.SaveAssets();
}
}
}
AssetDataBase创建资源:
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor; //在手机上上没有,需要使用条件编译
#endif
public class CreatAsset : MonoBehaviour {
[MenuItem("AssetDatabase/CreatAssetExample")]
static void CreatExample()
{
string str;
#if UNITY_EDITOR
//创建
Material material = new Material(Shader.Find("Specular"));
AssetDatabase.CreateAsset(material, "Assets/Materials/myMaterials.mat");
if(AssetDatabase.Contains(material))//如果存在
print(material.name);
//创建一个文件夹
str = AssetDatabase.CreateFolder("Assets", "NewFolder");
if (AssetDatabase.GUIDToAssetPath(str) != "")
print("Folder Asset Created !");
else
print(str);
#endif
}
}
3. AssetBundle
在Unity开发中,AssetBundle是重要的资源管理工具,它允许开发者将游戏资源如模型 、纹理、音频等打包成小型的、可被动态加载的压缩包。通过AssetBundle,开发者能够有效地管理大型游戏项目中的资源,实现按需加载,优化内存使用,并支持远程更新内容而不需重新发布整个应用程序。
特点:
(1) 资源分发 :允许将游戏内容划分成小块,按需下载,从而减少初始下载大小。
(2) 动态加载 :使得游戏可以在运行时动态加载和卸载资源,提升内存使用效率。
(3) 热更新 :支持远程更新AssetBundle来修复bug或添加新内容,无需提交新的应用程序版本。
打包 AssetBundle(编辑器脚本):
using UnityEngine;
using UnityEditor;
using System.IO;
public class BuildAssetBundle : ScriptableObject
{
public static void BuildAssetBundles()
{
// 创建构建目标对象
BuildTarget target = BuildTarget.StandaloneWindows;
// 设置构建目录
string assetBundleDirectory = Path.Combine("Builds", target.ToString());
// 如果目录不存在,则创建该目录
if (!Directory.Exists(assetBundleDirectory))
Directory.CreateDirectory(assetBundleDirectory);
// 设置AssetBundle构建参数
AssetBundleBuild[] assetBundleBuilds = new AssetBundleBuild[]
{
new AssetBundleBuild
{
assetBundleName = "mybundle",
assetNames = new[] { "Assets/Models/MyModel.prefab" }
}
};
// 执行构建
BuildPipeline.BuildAssetBundles(assetBundleDirectory, assetBundleBuilds, BuildAssetBundleOptions.None, target);
}
加载 AssetBundle(运行时):
using UnityEngine;
using System.Collections;
public class AssetBundleLoader : MonoBehaviour
{
IEnumerator LoadFromFileExample()
{
string bundlePath = "Assets/AssetBundles/mybundle";
// 从本地文件加载
AssetBundleCreateRequest request = AssetBundle.LoadFromFileAsync(bundlePath);
yield return request;
AssetBundle bundle = request.assetBundle;
if (bundle == null)
{
Debug.LogError("Failed to load AssetBundle!");
yield break;
}
// 加载包中的资源
AssetBundleRequest assetRequest = bundle.LoadAssetAsync<GameObject>("MyPrefab");
yield return assetRequest;
GameObject prefab = assetRequest.asset as GameObject;
Instantiate(prefab);
// 卸载AssetBundle,但保留已加载的资源
bundle.Unload(false);
}
IEnumerator LoadFromWebExample()
{
string url = "http://example.com/assetbundles/mybundle";
// 从网络加载
using (WWW www = new WWW(url))
{
yield return www;
AssetBundle bundle = www.assetBundle;
if (bundle != null)
{
// 加载并实例化资源
GameObject prefab = bundle.LoadAsset<GameObject>("MyPrefab");
Instantiate(prefab);
bundle.Unload(false);
}
}
}
void Start()
{
StartCoroutine(LoadFromFileExample());
// 或 StartCoroutine(LoadFromWebExample());
}
}
AssetBundle配置
在Unity编辑器的Inspector面板中找到AssetBundle的设置,可以为每一个想要打包的资源或预制体指定一个或多个AssetBundle名称。选择资源后,在面板的底部部分会出现一个”AssetBundle”的标签,其中包含”Variant”的字段,可以用于定义变体,这对于管理不同平台或语言的资源非常有用。
代码块示例:
// 用于设置AssetBundle名称的示例代码
AssetImporter importer = AssetImporter.GetAtPath("Assets/Models/MyModel.prefab");
importer.SetAssetBundleName("mybundle");
打包移动端StreamingAssets文件夹AssetBundle加载方式:
方法一:AssetBundle.LoadFromFile同步加载(推荐)
//加载AssetBundle
string abResPath = Path.Combine(Application.streamingAssetsPath, "3dprefabs");
AssetBundle ab = AssetBundle.LoadFromFile(abResPath);
//加载Asset
GameObject prefab = ab.LoadAsset<GameObject>("Cube");
//实例化
GameObject cube = Instantiate<GameObject>(prefab);
方法二:UnityWebRequest异步加载(支持服务器上在资源加载)
IEnumerator LoadAsset()
{
//注意:本地目录需要加上"file://"
string uri = "file://" + Application.streamingAssetsPath + "/3dprefabs";
UnityWebRequest request = UnityWebRequestAssetBundle.GetAssetBundle(uri, 0);
yield return request.SendWebRequest();
if (request.isNetworkError)
{
Debug.LogError(request.error);
}
//获取到ab包
AssetBundle ab = DownloadHandlerAssetBundle.GetContent(request);
//加载Asset
GameObject prefab = ab.LoadAsset<GameObject>("Cube");
//实例化
GameObject go = Instantiate<GameObject>(prefab);
}
关于资源AssetBundle热更新:
从服务器端下载AssetBundle到本地目录:Application.persistentDataPath。
加载资源的时候,优先去Application.persistentDataPath找看看有没有对应的资源,如果有,已Application.persistentDataPath中的资源为准,否则,再去Application.streamingAssets目录中找资源。
//你的资源文件
string resName = System.IO.Path.Combine(Application.persistentDataPath, "你的资源文件名");
if(System.IO.File.Exists(resName))
{
//在Application.persistentDataPath目录中加载资源
}
else
{
//在Application.streamingAssets目录中加载资源
}
最后 Addressables
Addressable Assets是 Unity 推出的新一代资源管理系统,基于 AssetBundle 但提供了更高层次的抽象,它解决了传统资源加载的痛点,提供了更智能、更灵活的资源管理方案。
核心特点:
(1) 按需加载:只加载需要的资源
(2) 自动内存管理:智能释放不需要的资源
(3) 支持热更新:可以动态更新资源
更详细的介绍推荐看博文:
openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)