Unity中的Resources类为开发者提供了一个方便的方式来加载和管理运行时资源。尽管它的使用简单直观,但为了充分发挥其潜力和避免常见的陷阱,还是需要对其有一些深入了解。
Resources类是Unity中的一个静态类,它提供了方法来加载存储在特定“Resources”文件夹内的资源。这些资源可以在编译时不与特定的场景或对象关联,但可以在运行时动态加载。
主要的形式写法
下面用Resources.Load
来举例:
1.返回一个 UnityEngine.Object 类型的对象。根据需要,你可能会将其转换为更具体的类型。
TextAsset myText = Resources.Load("Texts/MyTextFile") as TextAsset;
2.返回一个指定类型的对象,不需要再进行转换。使用泛型方法加载资源的好处是,你不需要使用类型转换 (‘as’关键字),因为返回值已经是期望的类型。
TextAsset myText = Resources.Load<TextAsset>("Texts/MyTextFile");
如何使用
资源的放置:为了通过Resources类加载,必须将资源放在名为"Resources"的文件夹内。你可以在项目中有多个此类文件夹,并且它们可以在其他文件夹内。
加载资源:
Sprite mySprite = Resources.Load<Sprite>("Sprites/MySprite");
上述代码将会加载位于"Resources/Sprites/"目录下的名为"MySprite"的精灵。
卸载资源:
Resources.UnloadAsset(mySprite);
注意事项和最佳实践
Resources.Load
: 从 “Resources” 文件夹中加载指定路径的资源
Resources.LoadAll
: 从 “Resources” 文件夹中加载指定路径下的所有资源
Resources.LoadAsync
: 从 “Resources” 文件夹中异步地加载资源
Resources.UnloadAsset
: 卸载从 Resources 文件夹加载的单个资源
Resources.UnloadUnusedAssets
: 卸载所有不再被引用的资源和对象
Resources.FindObjectsOfTypeAll
: 用于查询获取所有已加载的对象(包括非激活的)的方法
Resources.GetBuiltinResource
: 用于访问 Unity 内置的资源
Resources.InstanceIDToObject
: 允许将给定的实例ID转换为一个对象
Resources.InstanceIDToObjectList
: 用于将一组实例ID转换为Object列表
定义:
public static Object Load(string path);
public static Object Load(string path, Type systemTypeInstance);
参数:
path: 资源的相对路径,不需要包含文件扩展名。
systemTypeInstance: 指定要加载资源的类型,例如 typeof(GameObject)。这是可选参数。
返回:
返回加载的资源对象,需要根据实际情况转型为适当的类型。
使用注意:
示例:
假设有一个文件夹结构如下:
Assets/
│
└───Resources/
│
└───Sprites/
│ │
│ └───mySprite.png
│
└───Prefabs/
│
└───myPrefab.prefab
加载一个Sprite:
Sprite mySprite = Resources.Load<Sprite>("Sprites/mySprite");
加载一个预制体Prefab:
GameObject myPrefab = Resources.Load<GameObject>("Prefabs/myPrefab");
定义:
public static Object[] LoadAll(string path);
public static Object[] LoadAll(string path, Type systemTypeInstance);
参数:
path: 资源的相对路径。
systemTypeInstance: 指定要加载资源的类型,例如 typeof(GameObject)。这是可选参数。如果指定了这个参数,那么只会加载与此类型匹配的资源。
返回:
返回一个对象数组,包含加载的所有资源。需要根据实际情况转型为适当的类型。
示例:
假设有一个文件夹结构如下:
Assets/
│
└───Resources/
│
└───Sprites/
│
├───sprite1.png
├───sprite2.png
└───sprite3.png
加载一个文件夹中的所有 Sprite:
Sprite[] allSprites = Resources.LoadAll<Sprite>("Sprites");
定义
public static ResourceRequest LoadAsync(string path);
public static ResourceRequest LoadAsync(string path, Type type);
参数:
path: 资源的相对路径,相对于 “Resources” 文件夹,并且不应包含文件扩展名。
type: 指定要加载资源的类型
返回值:
返回一个 ResourceRequest 对象,它是 AsyncOperation 的子类,可以用来监控加载过程的进度、检查是否完成以及获取加载的资源。
示例:
想要异步加载一个名为 “MyTexture” 的纹理,其位于 “Resources/Textures” 目录下:
IEnumerator LoadTextureAsync()
{
ResourceRequest request = Resources.LoadAsync<Texture2D>("Textures/MyTexture");
yield return request;
if (request.isDone)
{
Texture2D loadedTexture = request.asset as Texture2D;
if (loadedTexture != null)
{
// 使用 loadedTexture 进行你的操作
}
}
}
在 MonoBehaviour 脚本的某个方法中通过 StartCoroutine(LoadTextureAsync()) 调用上述协程。
要注意的点:
定义
public static void UnloadAsset(Object assetToUnload);
参数:
assetToUnload: 需要释放的已加载的资源。这通常是一个通过 Resources.Load 或其他加载方法加载到内存中的资源。
示例:
假设你有一个在游戏中加载了很多大型纹理的场景。在玩家离开这个场景后,希望释放一些纹理以节省内存。你可以这样做:
Texture2D texture = Resources.Load<Texture2D>("Textures/BigTexture");
// 使用该纹理...
// 当不再需要纹理时
Resources.UnloadAsset(texture);
注意的事项:
定义
public static extern AsyncOperation UnloadUnusedAssets();
示例:
考虑这样一个场景:你有一个大型游戏关卡,其中加载了大量的纹理、3D模型、音频等资源。当玩家完成该关卡并进入下一个关卡时,许多先前的资源可能不再需要。此时,调用 Resources.UnloadUnusedAssets() 是个不错的选择。
public IEnumerator LoadNextLevel()
{
// 加载下一个关卡
SceneManager.LoadScene("NextLevel", LoadSceneMode.Single);
// 卸载不再使用的资源
yield return Resources.UnloadUnusedAssets();
}
注意的事项:
定义
public static Object[] FindObjectsOfTypeAll(Type type);
参数:
type: 要查找的对象的类型。
返回值:
返回一个包含所有找到的对象的数组。
示例:
1.查询所有摄像机:
Camera[] allCameras = Resources.FindObjectsOfTypeAll(typeof(Camera)) as Camera[];
2.查询所有的 Material:
Material[] allMaterials = Resources.FindObjectsOfTypeAll(typeof(Material)) as Material[];
注意的事项:
1.编辑器运行和打包后运行时差异:
2.性能开销: 这个方法可能会有一些性能开销,尤其是当有大量的对象需要查询时。建议不要在经常调用的代码(如 Update 方法)中使用它。
3.返回非激活的对象:与 GameObject.FindObjectOfType 和 GameObject.FindObjectsOfType 不同,这个方法会返回所有对象,包括那些在层次结构中被禁用的对象。
4.返回的对象范围:在编辑器中,这个方法还会返回像 Inspector 面板中的隐藏对象等其他不常见的对象。因此,需要谨慎处理返回的对象。
定义
public static T GetBuiltinResource<T>(string path) where T : Object;
其中,T 是您要加载资源的类型,path 是该资源的路径。
使用这个方法,您可以访问例如内置的材质、shader等资源。
示例:
假设你想加载 Unity 内置的“Standard” shader。你可以这样做:
Shader standardShader = Resources.GetBuiltinResource<Shader>("Standard.shader");
这将会返回一个指向内置“Standard” shader 的引用。
注意事项:
看到这里,你可能会有疑问:
如果我的材质球使用unity自带的shader,导入时unity会自动识别到并且为我的材质球赋值相应的shader啊,还要去用Resources.GetBuiltinResource的必要吗?
没错!当你在Unity中创建一个材质球并为其分配一个内置的shader,然后在另一个Unity项目中导入该材质球,Unity会尝试为这个材质球分配同样的shader(只要这个shader在导入的项目中是可用的)。
但Resources.GetBuiltinResource的主要目的不仅仅是处理材质球和shaders。它可以处理Unity的任何内置资源,例如纹理、meshes、预制体等。
考虑以下使用场景:
总的来说,虽然在许多常规开发任务中你可能不需要手动使用Resources.GetBuiltinResource,但在某些特定情境和高级应用中,它可以非常有用。
定义:
public static extern Object InstanceIDToObject(int instanceID);
参数:
instanceID: 要转换的实例ID。
返回值:
返回与提供的实例ID关联的对象。如果没有找到对象,则返回 null。
何时使用:
该方法在某些情况下可能会有用,特别是当你知道一个对象的实例ID,但不知道它具体是什么的时候。
但在大多数常规的开发情境中,你可能不会经常使用这个方法。它更常见于高级的工具开发或某些特定的编辑器脚本任务,其中你可能需要从其他数据源或工具中获得实例ID,然后需要获取到实例ID对应的实际对象。
注意:
示例:
假设你有一个工具,它从外部源获取实例ID,并且你想找到与该ID关联的对象。
int myInstanceID = 123456; // 这只是一个示例值,实际上你会从某个地方获取它
UnityEngine.Object obj = Resources.InstanceIDToObject(myInstanceID);
if (obj != null)
{
Debug.Log("找到具有实例ID的对象:" + obj.name);
}
else
{
Debug.Log("没有找到该实例ID的对象。");
}
总的来说,除非你正在处理特定于实例ID的工作需求,否则你可能不会经常用到这个方法。但了解它的存在和用途仍然是有益的,特别是对于高级开发和工具创建。
定义
public unsafe static void InstanceIDToObjectList(NativeArray<int> instanceIDs, List<Object> objects);
使用NativeArray来传递Instance IDs,这是一个Unity的结构,用于在C#和原生代码之间传递数据而不产生垃圾。
这个方法有几个关键点:
1.安全检查: 在转换前,方法会检查NativeArray是否已经被初始化,并确保提供的objects列表不为null。
2.清除对象列表: 如果提供的instanceIDs为空,它将清空objects列表。
3.转换: 如果提供了Instance IDs,它会调用内部的extern方法来进行实际的转换。
示例:
假设我们有一个场景,其中包含多个对象,我们想通过它们的Instance ID获取这些对象的引用。
void Start()
{
// 为简化起见,我们在这里使用了假的Instance IDs。
// 在实际应用中,你会从某些来源获得这些IDs。
NativeArray<int> sampleInstanceIDs = new NativeArray<int>(3, Allocator.Temp);
sampleInstanceIDs[0] = 1; // 假设的ID
sampleInstanceIDs[1] = 2; // 假设的ID
sampleInstanceIDs[2] = 3; // 假设的ID
ConvertInstanceIDsToObjectList(sampleInstanceIDs);
sampleInstanceIDs.Dispose();
}
public void ConvertInstanceIDsToObjectList(NativeArray<int> instanceIDs)
{
List<UnityEngine.Object> objectList = new List<UnityEngine.Object>();
Resources.InstanceIDToObjectList(instanceIDs, objectList);
// 打印转换后的对象名称
foreach (UnityEngine.Object obj in objectList)
{
Debug.Log(obj.name);
}
}
在这个简化的例子中,我们会假设已经有了这些IDs,并且将它们存储在NativeArray中。
使用Resources.InstanceIDToObjectList方法将这些IDs转换为实际的对象。
Resources类为Unity开发者提供了一个强大而灵活的工具,但是要确保正确并且高效地使用它。当正确使用时,它可以成为你的工具箱中的重要工具,帮助你创建更加动态和响应迅速的应用和游戏。