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

Unity学习之资源管理(Resources、AssetDatabase、AssetBundle、Addressable)

在 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);}}
}
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方法卸载所有未使用的资源:

// 卸载所有未使用的资源
Resources.UnloadUnusedAssets();

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; //在手机上上没有,需要使用条件编译
#endifpublic 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 !");elseprint(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);//加载AssetGameObject 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) 支持热更新:可以动态更新资源

更详细的介绍推荐看博文:

https://blog.csdn.net/linxinfa/article/details/122390621

http://www.dtcms.com/a/388787.html

相关文章:

  • LG P5138 fibonacci Solution
  • 删除UCPD监控服务或者监控驱动
  • 日语学习-日语知识点小记-构建基础-JLPT-N3阶段(33):文法運用第10回1+(考え方14)
  • 向量技术研究报告:从数学基础到AI革命的支柱
  • 802.1x和802.1Q之间关联和作用
  • 基于大模型多模态的人体体型评估:从“尺码测量”到“视觉-感受”范式
  • 更符合人类偏好的具身导航!HALO:面向机器人导航的人类偏好对齐离线奖励学习
  • Transformer多头注意力机制
  • git 分支 error: src refspec sit does not match any`
  • VN1640 CH5 I/O通道终极指南:【VN1630 I/O功能在电源电压时间精确度测试中的深度应用】
  • qt QHorizontalBarSeries详解
  • 半导体制造的芯片可靠性测试的全类别
  • MySQL 索引详解:原理、类型与优化实践
  • AI 重塑就业市场:哪些岗位将被替代?又会催生哪些新职业赛道?
  • mysql表分区备份太慢?如何精准“狙击”所需数据?
  • InVEST实践及在生态系统服务供需、固碳、城市热岛、论文写作等实际项目中应用
  • 数据库视图详解
  • C#并行处理CPU/内存监控:用PerformanceCounter实时监控,避免资源过载(附工具类)
  • 数据结构初阶——红黑树的实现(C++)
  • PS练习1:将风景图放到相框中
  • Seedream 4.0深度评测:新一代AI图像创作的革命性突破
  • Python中的异常和断言
  • java求职学习day32
  • 内存一致性模型(Memory Consistency Model)及其核心难度
  • Archery:一个免费开源的一站式SQL审核查询平台
  • 【中科院宁波材料技术与工程研究所主办】第五届机械自动化与电子信息工程国际学术会议(MAEIE 2025)
  • 政府支持再造视角下A区政府采购数字化发展问题及对策
  • 第三章:新婚
  • python+vue小区物业管理系统设计(源码+文档+调试+基础修改+答疑)
  • Android系统框架知识系列(二十二):Storage Manager Service - Android存储系统深度解析