Unity资源之Resources目录

文章讨论了Unity的Resources系统,指出其在内存管理和性能上的问题,特别是随着资源数量增加对启动时间和构建时间的影响。Resources系统适合于原型制作和少数特定场景,如托管预制件或静态配置数据。然而,由于其缺点,建议在项目成熟后避免使用,转而采用AssetBundleVariants进行内容调整和增量更新。

介绍

将资产存储在一个或多个名为Resources的文件夹中,并在运行时使用Resources API 从这些资产加载或卸载对象。


Resources System的最佳实践

不要使用它

出于以下几个原因,提出了这一强烈建议:

使用 Resources 文件夹使细粒度的内存管理更加困难

资源文件夹使用不当会增加应用程序启动时间和构建时间

随着 Resources 文件夹数量的增加,管理这些文件夹中的 Assets 变得非常困难

资源系统降低了项目向特定平台交付自定义内容的能力,并消除了增量内容升级的可能性

AssetBundle Variants 是 Unity 用于根据每个设备调整内容的主要工具


正确使用资源系统

有两个特定的用例,资源系统可以在不妨碍良好开发实践的情况下提供帮助:

1、Resources 文件夹的易用性使其成为快速制作原型的绝佳系统。 但是,当项目进入全面生产阶段时,应取消使用 Resources 文件夹。

2、 Resources 文件夹在一些琐碎的情况下可能会有用,如果内容是:
a. 通常在项目的整个生命周期中都需要
b. 不占用内存
c. 不容易打补丁,或者不会因平台或设备而异
d. 用于最小引导

第二种情况的示例包括用于托管预制件的 MonoBehaviour 单例,或包含第三方配置数据(例如 Facebook 应用程序 ID)的 ScriptableObjects。

Resources序列化

  构建项目时,所有名为“Resources”的文件夹中的资产和对象都合并到一个序列化文件中。 该文件还包含元数据和索引信息,类似于 AssetBundle。 如 AssetBundle 文档中所述,该索引包括一个序列化查找树,用于将给定对象的名称解析为其适当的文件 GUID 和本地 ID。 它还用于在序列化文件主体中的特定字节偏移处定位对象。

  在大多数平台上,查找数据结构是一个平衡的搜索树,其构建时间以 O(n log(n)) 的速度增长。 随着资源文件夹中对象数量的增加,这种增长也会导致索引的加载时间以超线性方式增长。

  此操作不可跳过,发生在应用程序启动时,同时显示初始非交互式启动画面。 据观察,在低端移动设备上初始化包含 10,000 个资产的资源系统会耗费数秒,尽管实际上很少需要将资源文件夹中包含的大多数对象加载到应用程序的第一个场景中。

Unity 中,`Resources` 文件夹内的资源与外部资源在加载方式和使用场景上有显著差异,主要体现在资源的打包、加载机制、访问权限和性能优化等方面。 ### `Resources` 文件夹内的资源 - **打包与访问权限**:`Resources` 文件夹中的资源在构建时会被统一打包进 `.assets` 文件块,这些资源在运行时可以通过 `Resources.Load()` 进行访问。由于资源在打包时已经压缩和加密,因此外部无法直接访问原始资源文件[^4]。 - **加载方式**:`Resources.Load()` 是同步加载方法,传入的是项目内的相对路径,不需要文件后缀名。例如,加载一个名为 `example` 的预制体,只需使用 `Resources.Load<GameObject>("example")`。然而,这种加载方式会在第一次实例化时才真正完成资源的加载,可能导致首次使用时出现卡顿现象[^2]。 - **使用场景**:`Resources` 文件夹适合存放需要在运行时动态加载的资源,例如预制体、纹理、音频等。由于资源被打包进项目,因此适合存储不会频繁更新的资源,以避免不必要的包体增大[^4]。 ### `Resources` 文件夹外的资源 - **打包与访问权限**:`Resources` 文件夹外的资源不会被打包进 `.assets` 文件块,这意味着它们可以以未加密和未压缩的形式存在于发布包中。例如,`StreamingAssets` 文件夹中的资源可以直接通过文件系统访问,适合存储二进制文件,如视频、音频或自定义数据文件[^3]。 - **加载方式**:对于外部资源,通常需要使用 `WWW` 或 `UnityWebRequest` 进行加载。这两种方法都支持从本地文件系统或远程服务器加载资源,并且需要传入完整的路径和文件后缀名。`WWW` 必须在协程中使用,且需要通过 `yield return` 等待加载完成[^5]。 - **使用场景**:外部资源适合存储需要动态更新或不需要 Unity 引擎直接管理的资源。例如,`StreamingAssets` 可以用于存储游戏中的补丁文件或用户生成的内容,而远程资源可以通过 `UnityWebRequest` 从服务器下载并动态加载[^3]。 ### 加载方式对比 - **同步 vs 异步**:`Resources.Load()` 是同步加载方法,适合在不需要等待资源加载的情况下使用,但可能导致首次实例化时的性能问题。相比之下,`WWW` 和 `UnityWebRequest` 提供了异步加载的能力,可以在加载资源时避免阻塞主线程,适合处理大文件或远程资源[^5]。 - **路径与后缀**:`Resources.Load()` 使用项目内的相对路径,且不需要文件后缀名;而 `WWW` 和 `UnityWebRequest` 需要完整的路径和文件后缀名,且路径可以是本地文件系统或远程服务器地址。 - **资源管理**:`Resources` 文件夹内的资源在构建时被打包,适合存储静态资源;外部资源则更适合存储需要动态更新或不需要 Unity 引擎直接管理的资源。 ### 示例代码 以下是一个使用 `Resources.Load()` 加载资源的示例代码: ```csharp using UnityEngine; public class LoadResource : MonoBehaviour { void Start() { // 从Resources文件夹加载一个预制体 GameObject prefab = Resources.Load<GameObject>("example"); if (prefab != null) { Instantiate(prefab, Vector3.zero, Quaternion.identity); } } } ``` 以下是一个使用 `UnityWebRequest` 加载外部资源的示例代码: ```csharp using UnityEngine; using UnityEngine.Networking; using System.Collections; public class LoadExternalResource : MonoBehaviour { IEnumerator Start() { // 从远程服务器加载一个纹理 UnityWebRequest request = UnityWebRequestTexture.GetTexture("http://example.com/image.png"); yield return request.SendWebRequest(); if (request.isNetworkError || request.isHttpError) { Debug.Log(request.error); } else { Texture2D texture = ((DownloadHandlerTexture)request.downloadHandler).texture; GetComponent<Renderer>().material.mainTexture = texture; } } } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值