UFL5-1——Resource资源加载模块的具体实现

前置知识点

  1. C#中Dictionary​相关知识点(C#四部曲之C#进阶中)
  2. C#中委托事件相关知识点(C#四部曲之C#进阶中)
  3. Unity中Resources相关知识点(Unity四部曲之Unity基础中)
  4. Unity中协同程序相关知识点(Unity四部曲之Unity基础中)

Resources资源加载模块的具体实现

  1. 创建 ResourcesManager​ 继承 不继承MonoBehaviour的单例模式基类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    using UnityEngine;
    using UnityEngine.Events;

    /// <summary>
    /// Resources 资源加载模块管理器
    /// </summary>
    public class ResManager : BaseManager<ResManager>
    {
    private ResManager() { }
    }
  2. 为它封装Resources​异步加载资源的相关方法(主要目的 避免异步加载的代码冗余)

    在之前我们使用Resources​异步加载需要额外声明一个协程,才能去调用异步加载资源的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    Texture tex

    void Start()
    {
    //通过协程 使用加载的资源
    StartCoroutine(Load());
    }

    IEnumerator Load()
    {
    ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/test");
    print(Time.frameCount);
    yield return rq; //向Unity协程调度器返回这种类型的变量,Unity就会识别出当前正在执行异步下载资源操作
    //Unity会自行判断该资源是否加载完毕了 加载完毕后才会继续执行后面的代码
    tex = rq.asset as Texture;
    }

    //使用获取的资源的函数
    private void OnGUI()
    {
    if (tex != null) //一定要确认获取到资源了才开始渲染GUI
    GUI.DrawTexture(new Rect(0, 0, 100, 100), tex);
    }

    因此可以将额外的协程方法声明封装到管理器内,采用让外部传入回调函数的方式来获取资源

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    // 异步加载资源的方法
    public void LoadAsync<T>(string path, UnityAction<T> callBack) where T : UnityEngine.Object
    {
    //要通过协同程序去异步加载资源
    MonoManager.Instance.StartCoroutine(ReallyLoadAsync<T>(path, callBack));
    }

    private IEnumerator ReallyLoadAsync<T>(string path, UnityAction<T> callBack) where T : UnityEngine.Object
    {
    //异步加载资源
    ResourceRequest req = Resources.LoadAsync<T>(path);
    //等待资源加载结束后,才会继续执行yield return后面的代码
    yield return req;
    //资源加载结束,将资源传到外部的委托函数去进行调用
    callBack(req.asset as T);
    }

    public void LoadAsync(string path, Type type, UnityAction<UnityEngine.Object> callBack)
    {
    MonoManager.Instance.StartCoroutine(ReallyLoadAsync(path, type, callBack));
    }

    private IEnumerator ReallyLoadAsync(string path, Type type, UnityAction<UnityEngine.Object> callBack)
    {
    ResourceRequest req = Resources.LoadAsync(path, type);
    yield return req;
    callBack(req.asset);
    }

    这样封装以后,异步加载的调用就只需要额外传入一个回调函数即可

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void Start()
    {
    ResManager.Instance.LoadAsync<GameObject>("Test", (obj) =>
    {
    Instantiate(obj);
    });

    ResManager.Instance.LoadAsync("Test", typeof(GameObject), (obj) =>
    {
    Instantiate(obj as GameObject);
    });
    }
  3. 直接封装Resources​同步加载资源的相关方法

    1
    2
    3
    4
    5
    // 同步加载资源的方法
    public T Load<T>(string path) where T : UnityEngine.Object
    {
    return Resources.Load<T>(path);
    }
  4. 直接封装资源卸载相关方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    // 异步卸载对应没有使用的Resources相关资源
    public void UnloadUnusedAssets(UnityAction callBack)
    {
    MonoManager.Instance.StartCoroutine(ReallyUnloadUnusedAssets(callBack));
    }

    private IEnumerator ReallyUnloadUnusedAssets(UnityAction callBack)
    {
    AsyncOperation ao = Resources.UnloadUnusedAssets();
    yield return ao;
    callBack?.Invoke();
    }

使用示例

假设要异步加载Resources文件夹下Test预设体,因此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using System;
using UnityEngine;

public class Main : MonoBehaviour
{
void Start()
{
ResManager.Instance.LoadAsync<GameObject>("Test", (obj) =>
{
Instantiate(obj);
});

ResManager.Instance.LoadAsync("Test", typeof(GameObject), (obj) =>
{
Instantiate(obj as GameObject);
});
}
}

场景上加载了两个:image

具体代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;

/// <summary>
/// Resources 资源加载模块管理器
/// </summary>
public class ResManager : BaseManager<ResManager>
{
private ResManager() { }

/// <summary>
/// 同步加载资源的方法
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
/// <param name="path"></param>
/// <returns></returns>
public T Load<T>(string path) where T : UnityEngine.Object
{
return Resources.Load<T>(path);
}

/// <summary>
/// 异步加载资源的方法
/// </summary>
/// <typeparam name="T">资源类型</typeparam>
/// <param name="path">资源路径(Resources下的)</param>
/// <param name="callBack">加载结束后的回调函数</param>
public void LoadAsync<T>(string path, UnityAction<T> callBack) where T : UnityEngine.Object
{
//要通过协同程序去异步加载资源
MonoManager.Instance.StartCoroutine(ReallyLoadAsync<T>(path, callBack));
}

private IEnumerator ReallyLoadAsync<T>(string path, UnityAction<T> callBack) where T : UnityEngine.Object
{
//异步加载资源
ResourceRequest req = Resources.LoadAsync<T>(path);
//等待资源加载结束后,才会继续执行yield return后面的代码
yield return req;
//资源加载结束,将资源传到外部的委托函数去进行调用
callBack(req.asset as T);
}

/// <summary>
/// 异步加载资源的方法
/// </summary>
/// <param name="path">资源路径(Resources下的)</param>
/// <param name="type">资源类型</param>
/// <param name="callBack">加载结束后的回调函数</param>
public void LoadAsync(string path, Type type, UnityAction<UnityEngine.Object> callBack)
{
//要通过协同程序去异步加载资源
MonoManager.Instance.StartCoroutine(ReallyLoadAsync(path, type, callBack));
}

private IEnumerator ReallyLoadAsync(string path, Type type, UnityAction<UnityEngine.Object> callBack)
{
//异步加载资源
ResourceRequest req = Resources.LoadAsync(path, type);
//等待资源加载结束后,才会继续执行yield return后面的代码
yield return req;
//资源加载结束,将资源传到外部的委托函数去进行调用
callBack(req.asset);
}

/// <summary>
/// 指定卸载一个资源
/// </summary>
/// <param name="assetToUnload">要卸载的资源</param>
public void UnloadAsset(UnityEngine.Object assetToUnload)
{
Resources.UnloadAsset(assetToUnload);
}

/// <summary>
/// 异步卸载对应没有使用的Resources相关资源
/// </summary>
/// <param name="callBack">回调函数</param>
public void UnloadUnusedAssets(UnityAction callBack)
{
MonoManager.Instance.StartCoroutine(ReallyUnloadUnusedAssets(callBack));
}

private IEnumerator ReallyUnloadUnusedAssets(UnityAction callBack)
{
AsyncOperation ao = Resources.UnloadUnusedAssets();
yield return ao;
callBack?.Invoke();
}
}