Resources资源同步加载、异步加载、卸载

1. Unity Resources 同步加载资源(Resources.Load)

  • Unity 提供了 Resources 文件夹和 API 来动态加载资源,可以在运行时通过代码获取所需资源,避免繁琐的拖拽操作。

1.1 作用

  • 动态加载 Resources 文件夹下指定路径的资源
  • 减少场景和组件对资源的依赖,提高灵活性
  • 可以在运行时实例化预设体、播放音效、读取文本等

1.2 常用资源类型

类型 Unity 类型 注意事项
预设体对象 GameObject 加载后需实例化
音效文件 AudioClip 可直接赋值给 AudioSource
文本文件 TextAsset 支持 .txt, .xml, .json
图片文件 TextureSprite 可直接用于 UI 或材质
其它类型 自定义类型 需要什么类型就用什么类型

1.3 资源同步加载

  • 普通方法(不推荐)
// 加载预设体资源
Object obj = Resources.Load("Cube");
Instantiate(obj);
// 加载音效
public AudioSource audioSource;
AudioClip clip= Resources.Load("Music/拔刀声") as AudioClip;
audioSource.clip = clip;
audioSource.Play();
// 加载文本
public Text text;
TextAsset ta = Resources.Load("Text/text") as TextAsset;
text.text = ta.text;
// 加载图片
public Image img;
Sprite sprite = Resources.Load("Sprite/图片") as Sprite;
img.sprite = sprite;
//加载RawImage图片/物体纹理
public RawImage rawImage;
Texture tex = Resources.Load("Texture/壁纸") as Texture;
rawImage.texture = tex;

//当资源重名时 需要指定资源类型加载
tex = Resources.Load("Texture/壁纸", typeof(Texture)) as Texture;

// 加载同名资源的所有对象
public Texture tex;
Object[] objs = Resources.LoadAll("Texture/壁纸");
for(int i = 0; i < objs.Length; i++)
{
    if(objs[i] is Texture)
        tex = (Texture)objs[i];
}
  • 泛型方法(推荐)
// 加载预设体资源
GameObject obj = Resources.Load<GameObject>("Cube");
Instantiate(obj);
// 加载音效
public AudioSource audioSource;
AudioClip clip= Resources.Load<AudioClip>("Music/拔刀声");
audioSource.clip = clip as AudioClip;
audioSource.Play();
// 加载文本
public Text text;
TextAsset ta = Resources.Load<TextAsset>("Text/text");
text.text = ta.text;
// 加载图片
public Image img;
Sprite sprite = Resources.Load<Sprite>("Sprite/图片");
img.sprite = sprite;
//加载纹理
public RawImage rawImage;
Texture tex = Resources.Load<Texture>("Texture/壁纸");
rawImage.texture = tex;
//不用担心资源重名问题,泛型加载已经指定了类型,但也加载不了所有同名资源

1.4. 注意事项

  1. 预设体需要实例化,其它资源可直接使用
  2. 同名资源可能冲突,可使用 Resources.LoadAll 或指定类型解决
  3. Resources 目录内容会打包到最终游戏中,过多使用会影响包体大小和内存

2. Unity Resources 异步加载资源(Resources.LoadAsync)

  • 在游戏开发中,同步加载大资源可能造成卡顿,异步加载通过内部线程加载资源,不会阻塞主线程

注意:异步加载不能立即获得资源,至少需要等一帧才能使用。

2.1 异步加载方法

  • 方法一 通过 completed 订阅事件(该方法可以在资源加载完成后处理一些逻辑)
public class Test()
{
  public Sprite sprite;
  public GameObject obj;
  void Start()
  {
    // 异步加载 Sprite
    ResourceRequest rq = Resources.LoadAsync<Sprite>("Sprite/图片");
    // 异步加载 GameObject
    ResourceRequest rq2 = Resources.LoadAsync<GameObject>("Cube/Cube");
    // 刚刚执行了异步加载,资源还没有加载完毕(至少等待一帧) 不能直接获取
    // sprite = rq.asset as Sprite;

    // 当资源加载结束 会自动调用completed 执行里面订阅的方法
    rq1.completed += LoadOver1;
    rq2.completed += LoadOver2;
  }
  // 获取加载完成的资源
  private void LoadOver1(AsyncOperation rq)
  {
    sprite = (rq as ResourceRequest).asset as Sprite;
  }
  private void LoadOver2(AsyncOperation rq)
  {
    obj = (rq as ResourceRequest).asset as GameObject;
  }
}

只能在加载完成后进行一些操作,加载过程中不能进行操作,进度条功能是做不了的


2.2 协程方式

public class Test()
{
  public Sprite sprite;
  public GameObject obj;
  void Start()
  {
    StartCoroutine(Load());
  }
  IEnumerator Load()
  {
      ResourceRequest rq = Resources.LoadAsync<Sprite>("Sprite/图片");
      while(!rq.isDone)
      {
          // 可获取加载进度 用来制作进度条
          Debug.Log(rq.progress);
          yield return null; // 等待下一帧继续
      }
      // 获取加载完成的资源
      sprite = rq.asset as Sprite; 
      obj = rq.asset as GameObject;
  }
}

可在协程中处理复杂逻辑,如同时加载多个资源、更新进度条


2.3 注意事项

  1. LoadAsync相当于新开一个线程加载资源
  2. 异步加载资源至少要等一帧才能使用,否则资源可能还未加载完成(不能直接rq.asset获取资源)。
  3. 协程异步加载本质:利用 迭代器 + 协程调度器 来分步执行加载逻辑。

3. Unity Resources资源卸载

  • 使用 Resources.Load() 加载资源时,Unity 会将加载的资源缓存在内存中。当第二次加载同一资源时,Unity 会从缓存直接返回,而不会重新创建资源实例。
  • 不会浪费额外内存(因为只加载一次),重复调用 Load() 会触发查找和获取缓存的开销会浪费性能
  • 物体销毁、切换场景 → 通过Resources加载的资源 在 Resources 缓存中还是存有加载路径,仍然存在在内存中,不会自动卸载

3.1 卸载资源方法

// 卸载指定资源,不能卸载 GameObject 资源(包括 Prefab),因为它们依赖实例化使用,只能用于无需实例化的资源类型,例如:Sprite、AudioClip、TextAsset、其它非 GameObject 的可加载资源
Sprite sprite = Resources.Load<Sprite>("Sprite/图片");
Resources.UnloadAsset(sprite);
// 卸载未使用的资源 一般在过场景时和GC一起使用
Resources.UnloadUnusedAssets();
GC.Collect();

Resources.UnloadAsset 只能卸载非实例化资源。如果你已经实例化了 Prefab,那么实例化出来的对象必须用 Destroy() 清理,UnloadAsset 只会清掉原始资源。
大型项目一般使用 AssetBundle 或 Addressables 管理资源,而不是 Resources 文件夹

posted @ 2025-12-10 21:01  高山仰止666  阅读(32)  评论(0)    收藏  举报