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

Unity基础学习(九)Resources资源同步与异步加载

        为什么需要进行资源加载,是避免直接将资源模型内容,直接进行拖拽,导致管理混乱。通过代码进行统一管理,自动化配置。

一、什么是Resources资源加载

定义
        Resources资源加载是Unity提供的一种动态加载资源的方式,允许通过代码从项目中标记为"Resources"的特殊文件夹中加载资源。这些资源在打包时会统一合并处理,无需通过拖拽方式手动赋值。

Resources特点:

1、必须将资源存放在Resources文件夹(可嵌套在子文件夹)
2、允许存在多个Resources文件夹,通过API加载时候 他会自己去每个文件夹寻找资源
3、所有Resources文件夹内容会被合并打包成一个总目录
4、通过路径名访问,无需后缀名(如.prefab)

二、有哪些资源加载方式

主要分为三种形式:
同步加载(立即加载)
Resources.Load():直接阻塞主线程直到加载完成
适用场景:小资源或初始化阶段

异步加载(后台加载)
Resources.LoadAsync():不阻塞主线程
适用场景:大资源或需要优化流畅性时

批量加载
Resources.LoadAll():加载指定路径下所有资源

三、怎么进行资源同步加载

核心API
// 泛型方法(推荐)
T Resources.Load<T>(string path) where T : Object;// 非泛型方法
Object Resources.Load(string path, System.Type type);

加载各种对象的示例:

1. 加载预设体

// 加载预设体资源(未实例化)
GameObject prefab = Resources.Load<GameObject>("Cube");
// 实例化到场景中
Instantiate(prefab);

注意:

(1)加载的预设体只是配置数据,需通过Instantiate生成实例
(2)假设Cube.prefab位于Resources/Prefabs/Cube,则路径为"Prefabs/Cube" 

2. 加载音频

AudioClip clip = Resources.Load<AudioClip>("Music/BkMusic");
audioSource.clip = clip;
audioSource.Play();

直接使用:音频资源加载后可直接赋值给AudioSource组件 ,同样需要注意路径

3. 加载文本

TextAsset textAsset = Resources.Load<TextAsset>("Txt/Text");
Debug.Log(textAsset.text); // 获取文本内容

(1)支持txt/.xml/.json等文本格式
(2)通过text属性获取字符串,bytes获取二进制数据 

(同样仍需注意路径)

4. 加载图片

Texture texture = Resources.Load<Texture>("Picture/4");
// GUI显示示例
void OnGUI() {GUI.DrawTexture(new Rect(0,0,100,100), texture);
}

类型匹配:确保加载类型与资源类型一致(Texture2D/Sprite等) 

(同样仍需注意路径)

5. 处理同名资源

// 指定类型加载
Texture tex = Resources.Load("Picture/4", typeof(Texture)) as Texture;// 加载所有同名资源
Object[] all = Resources.LoadAll("Picture/4");
foreach(Object obj in all){if(obj is Texture2D) {// 使用Texture2D资源}
}

 (同样仍需注意路径)

四、怎么进行异步加载

方式1:通过事件回调异步加载

using UnityEngine;public class AsyncLoadExample_Event : MonoBehaviour
{private Texture2D loadedTexture;void Start(){// 开始异步加载ResourceRequest request = Resources.LoadAsync<Texture2D>("Textures/MyTexture");// 注册完成事件request.completed += OnLoadCompleted;}// 加载完成回调private void OnLoadCompleted(AsyncOperation operation){// 类型转换ResourceRequest request = operation as ResourceRequest;// 错误检查if (request.asset == null){Debug.LogError("加载失败,请检查路径或资源是否存在");return;}// 获取资源loadedTexture = request.asset as Texture2D;Debug.Log("异步加载完成,纹理尺寸:" + loadedTexture.width + "x" + loadedTexture.height);// 使用资源(示例:在屏幕上绘制)// 注意:实际使用时应通过Material或UI组件显示}void OnGUI(){if (loadedTexture != null){GUI.DrawTexture(new Rect(10, 10, 100, 100), loadedTexture);}}void OnDestroy(){// 手动释放资源if (loadedTexture != null){Resources.UnloadAsset(loadedTexture);}}
}

有几个关键注意点:

(1)必须是将需要加载的资源放在一个全局变量中,即是类的成员变量,而非函数的成员变量。

(2) 进行事件监听时,必须是ResourceRequest 类型的变量中completed才具备表示事件完成后,需要执行的操作。

(3)切记将AsyncOperation 转换为实际上使用的ResourceRequest 委托。

(4)切记通过request.asset as Texture2D这样来进行实际转换。

具体原理:

        Unity的资源异步加载通过事件回调机制实现,其核心原理围绕主线程与后台线程的协同工作展开。整个过程始于开发者调用Resources.LoadAsync方法发起异步加载请求,此时Unity会创建一个ResourceRequest对象作为加载任务的核心载体。该对象不仅记录了资源路径、加载进度等元信息,更重要的是维护了一个完成事件completed的委托链,这是回调机制的关键枢纽。
       当加载请求启动后,Unity的内部线程管理系统会将实际加载工作分配到后台线程执行。后台线程首先根据资源路径定位具体的物理文件(需确保资源位于项目的Resources目录或子目录下),随后执行文件读取、数据解码和资源反序列化等耗时操作。这一阶段完全独立于主线程运行,避免了主线程的阻塞。值得注意的是,不同类型的资源(如纹理、音频、预制体等)在此阶段会经历不同的处理流程,例如纹理需要解析图像格式,音频文件需进行解码采样,预制体则涉及组件结构的重建。
        后台线程完成资源处理后,Unity通过内部的消息队列机制将加载结果传递回主线程。这一跨线程通信过程采用线程安全的数据交换策略,通常涉及双重缓冲或原子操作来确保数据一致性。当主线程在下一帧的更新周期中检测到加载任务已完成时,会遍历ResourceRequest对象的completed事件列表,逐个触发注册的回调方法。值得注意的是,所有回调都是在主线程上下文中执行的,这使得我们可以直接在回调中安全调用Unity的API(如实例化游戏对象、修改组件属性等),无需担心跨线程访问的问题。
       事件回调的执行过程伴随着类型转换和错误处理的关键步骤。由于ResourceRequest的asset属性返回的是通用的UnityEngine.Object类型,我们需要通过as关键字将其转换为具体的资源类型(如Texture2D或AudioClip)。这种显式转换不仅确保了类型安全,也为错误检测提供了契机——当资源路径错误或类型不匹配时,转换结果会为null。所以我们可以进行错误检测。

方式2:通过协程异步加载

using UnityEngine;
using System.Collections;public class ResourceLoader : MonoBehaviour
{[Header("加载配置")]public string texturePath = "Textures/MyTexture"; // 图片资源路径public string prefabPath = "Prefabs/MyPrefab";    // 预制体路径private Texture2D loadedTexture;private GameObject loadedPrefab;void Start(){// 显式启动协程StartCoroutine(LoadResources());}IEnumerator LoadResources(){// 加载纹理yield return StartCoroutine(LoadTexture(texturePath));// 加载预制体(等待纹理加载完成后执行)yield return StartCoroutine(LoadPrefab(prefabPath));// 所有资源加载完成后初始化InitializeGame();}IEnumerator LoadTexture(string path){ResourceRequest request = Resources.LoadAsync<Texture2D>(path);while (!request.isDone){Debug.Log($"正在加载纹理 [{path}] 进度:{request.progress:P0}");yield return null;}if (request.asset == null){Debug.LogError($"纹理加载失败:{path}");yield break;}loadedTexture = request.asset as Texture2D;Debug.Log($"纹理加载完成:{loadedTexture.name} ({loadedTexture.width}x{loadedTexture.height})");}IEnumerator LoadPrefab(string path){ResourceRequest request = Resources.LoadAsync<GameObject>(path);while (!request.isDone){Debug.Log($"正在加载预制体 [{path}] 进度:{request.progress:P0}");yield return null;}if (request.asset == null){Debug.LogError($"预制体加载失败:{path}");yield break;}loadedPrefab = request.asset as GameObject;Debug.Log($"预制体加载完成:{loadedPrefab.name}");}void InitializeGame(){// 实例化预制体if (loadedPrefab != null){GameObject instance = Instantiate(loadedPrefab);Debug.Log($"实例化对象:{instance.name}");}// 使用纹理(示例:创建材质球)if (loadedTexture != null){Material mat = new Material(Shader.Find("Standard"));mat.mainTexture = loadedTexture;Debug.Log($"创建材质球:{mat.name}");}}void OnDestroy(){// 释放资源if (loadedTexture != null) Resources.UnloadAsset(loadedTexture);if (loadedPrefab != null) Resources.UnloadAsset(loadedPrefab);Resources.UnloadUnusedAssets();}
}

五、怎么进行资源卸载

提问:当反复加载资源时,会重复消耗更多的内存吗?

回答:不是的,如果已经加载到内存时,就不会再反复加载相同的内容了。但是会消耗CPU的计算。

1. 指定资源卸载 Resources.UnloadAsset

适用对象:

纹理(Texture) ✅
音频(AudioClip) ✅
文本(TextAsset) ✅
材质(Material) ✅
不可用:预制体/GameObject ❌

void Update()
{if(Input.GetKeyDown(KeyCode.A)){// 加载到内存缓存text = Resources.Load<Texture>("Pic");}if(Input.GetKeyUp(KeyCode.A)){// 从缓存中移除Resources.UnloadAsset(text);// 必须解除引用text = null; }
}

注意:

(1)一个是路径必须正确

(2)二个是释放完要解除引用,不然就内存泄露了。 

2. 批量卸载 Resources.UnloadUnusedAssets

        扫描内存中未被任何MonoBehaviour引用的资源

例如切换场景:

IEnumerator SwitchScene()
{// 卸载当前场景资源Resources.UnloadUnusedAssets();System.GC.Collect();// 等待清理完成yield return new WaitForEndOfFrame();// 加载新场景SceneManager.LoadScene("NewScene");
}

 七、总结核心API与属性速查表

属性/方法输入参数输出类型说明与示例
Resources.Load<T>path (string)T同步加载泛型方法
Texture tex = Resources.Load<Texture>("Textures/Icon");
Resources.Loadpath (string), type (Type)Object同步加载指定类型
Object obj = Resources.Load("Audio/Sound", typeof(AudioClip));
Resources.LoadAsync<T>path (string)ResourceRequest异步加载资源
ResourceRequest req = Resources.LoadAsync<GameObject>("Prefabs/Player");
Resources.LoadAllpath (string)T[]加载目录下所有资源
TextAsset[] texts = Resources.LoadAll<TextAsset>("Configs");
Resources.UnloadAssetasset (Object)void卸载非GameObject资源
Resources.UnloadAsset(loadedTexture);
Resources.UnloadUnusedAssetsAsyncOperation清理未引用资源
Resources.UnloadUnusedAssets();
Resources.FindObjectsOfTypeAlltype (Type)Object[]获取所有指定类型对象
Material[] mats = Resources.FindObjectsOfTypeAll<Material>();
Resources.GetBuiltinResourcepath (string)T获取内置资源
Material mat = Resources.GetBuiltinResource<Material>("Default-Diffuse.mat");

ResourceRequest关键属性

属性类型说明
isDonebool加载是否完成
if(request.isDone) { /* ... */ }
progressfloat加载进度(0~1)
Debug.Log(request.progress);
assetObject加载完成的资源
Texture tex = request.asset as Texture;

路径规则与注意事项

类别规则
路径格式不包含Resources文件夹名和文件扩展名
示例:"UI/Icons/Sword"对应Resources/UI/Icons/Sword.png
平台差异移动端路径大小写敏感,PC/Mac不敏感
内存特性首次加载后资源常驻内存缓存,重复加载无内存开销

卸载策略对照表

方法适用场景限制
UnloadAsset释放特定非实例化资源不可用于GameObject
UnloadUnusedAssets场景切换时批量清理需配合GC.Collect()使用

异步加载方式对比

方式优点缺点
事件回调代码简洁无法跟踪进度
协程支持进度监控需处理协程嵌套

相关文章:

  • 如何在 Linux 系统中永久禁用交换分区 ?
  • 实验绘图参考-0525版(自用)
  • PostgreSQL 与 MongoDB:为您的数据项目选择合适的数据库
  • 记录第一次正式收到SCI期刊论文的审稿
  • Ubantu22.04离线安装、卸载mysql8.0.39并设置开机自启
  • 深入理解 Linux 的 set、env 和 printenv 命令
  • 使用粘滞键修改windows密码
  • 医学写作供应商管理全流程优化
  • 前端课设Web2
  • 微服务——网关
  • 第九章 云平台开发
  • 测试工程师如何通俗理解和入门RAG:从“查资料”到“写答案”的智能升级
  • 如何使用Webpack实现异步加载?
  • OC语言学习——Foundation框架回顾及考核补缺
  • Three.js 海量模型加载性能优化指南
  • 页表:从虚拟内存到物理内存的转换
  • 11.8 LangGraph生产级AI Agent开发:从节点定义到高并发架构的终极指南
  • 资源-又在网上淘到金了-三维模型下载
  • 【AI论文】QuickVideo:通过系统算法协同设计实现实时长视频理解
  • window 显示驱动开发-Direct3D 呈现性能改进(四)
  • 辽宁模板网站建设公司/湖南正规seo优化
  • 重庆电商网站建设/关键词在线听免费
  • 深圳网站建设团队/如何创建一个自己的网站
  • 哪里有广告设计制作的培训/seo新方法
  • 营销型网站制作服务商/传媒网站
  • 网站建设后台管理/百度关键词搜索趋势