当前位置:   article > 正文

Unity--异步加载资源_unity异步加载资源

unity异步加载资源

Unity–异步加载资源

0. 异步加载资源简介

在Unity中,异步加载资源是一种优化游戏性能的重要手段,特别是在处理大型资源或需要平滑过渡的场景时。以下是关于Unity中异步加载资源的内容总结:

1. 为什么使用异步加载

  • 避免卡顿:异步加载可以在不冻结游戏主线程的情况下加载资源,从而避免游戏过程中的卡顿。
  • 提高性能:在加载资源的同时,游戏可以继续运行,提高整体性能。

2. 异步加载方法

  • Resources.LoadAsync:与Resources.Load类似,但以异步方式加载资源。例如,Resources.LoadAsync<GameObject>("Cube")

3. 使用Resources.LoadAsync

  • 基本用法Resources.LoadAsync返回一个ResourceRequest对象,通过该对象可以检查加载进度和获取加载结果。因为加载资源分为两个阶段:加载中和加载完毕

  • 示例

    public class LoadSource : MonoBehaviour
    {
        // 异步加载数据
        // 加载图片
    
        private Texture texture;
    
        private void Start()
        {
            MyAsychonizedLoad();
        }
        void MyAsychonizedLoad()
        {
            // 异步加载--会消耗帧, 所以有很多资源的时候需要写一个加载的进度条
            ResourceRequest re = Resources.LoadAsync<Texture>("Pictures/Picture");
            // 是否加载结束
            re.completed += ResourceCompleted;
            // 打印帧数
            Debug.Log(Time.frameCount);
        }
       
        // 加载完毕回调函数
        private void ResourceCompleted(AsyncOperation obj)
        {
            Debug.Log("资源加载完毕");
            // 打印帧数
            Debug.Log(Time.frameCount);
            // 对资源赋值
            // 先类型转换 在赋值
            ResourceRequest rq = obj as ResourceRequest;
            if (rq != null)
            {
                texture = rq.asset as Texture;
            }   
        }
    
        // 测试加载好的图片
        private void OnGUI()
        {
            if (texture != null) // 加载中的时候texture还是nuLl的
            {
                GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), texture);
            }
            
        }
    }
    
    
    • 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

4. 使用协程来异步加载资源

  • 为什么使用协程来加载资源, 因为协程虽不是线程但是轻量级的线程,可以分担主线程的压力.
  • 为什么可以用协程来异步加载资源. 因为异步加载资源ResourceRequest和 协程Coroutine都有继承了YieldInstruction这个类. 由于加载资源是从加载中到加载完毕,是需要消耗一定的时间,这个时间我们不知道是多少,这取决于内存的大小和资源的大小. 而yeild return紧紧跟着的内容可以是 null 1 2 自定类, 等待时间等. 因此,利用等待时间来加载资源.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadResourcesAsychonized: MonoBehaviour
{
    // 异步加载数据 -- 加载图片
    private Texture texture;

    private void Start()
    {
        // 异步加载--协程模式加载
        StartCoroutine(LoadOver());
        StartCoroutine(LoadOverDetial());
    }

    // 使用协程加载资源
    IEnumerator LoadOver()
    {
        // 加载资源--图片
        ResourceRequest rq = Resources.LoadAsync<Texture>("Pictures/Picture");
        // ResourceRequest翻译为请求的资源-
        //该资源有很多信息: 是否加载完毕,加载优先级,当前加载进度,加载的资源,场景加载好就激活该资源(bool allowSceneActivation)
        // 打印帧数
        Debug.Log(Time.frameCount);
        // 加载完毕
        yield return rq;
        // 加载完毕继续执行, 为什么yield return rq呢? 因为ResourceRequest继承了AsyncOperation
        // 而AsyncOperation 继承了 YieldInstruction 且协程Coroutine中也是继承了 YieldInstruction
        // 所以大家继承了同一个类 当你使用 yield return rq; 时,
        // 你实际上是在告诉协程:“在这里暂停执行,直到 rq 这个异步操作完成。”
        // 这意味着协程会在这里等待,直到资源加载完成。
        // 一旦资源加载完成,协程就会从 yield return 语句的下一条语句继续执行。

        // 打印帧数
        Debug.Log(Time.frameCount);
        // 资源加载完毕后,继续执行
        texture = rq.asset as Texture;  // 将资源转换为我们需要资源的类型
    }

    // 协程异步加载详解
    IEnumerator LoadOverDetial()
    {
        // 加载资源
        ResourceRequest rq = Resources.LoadAsync<Texture>("Pictures/Picture");
        // 打印帧数
        Debug.Log(Time.frameCount);

        // 还可以获得加载的进度,是否加载完毕等数据
        while (!rq.isDone)
        {
            Debug.Log("资源加载优先级" + rq.priority);
            Debug.Log("资源加载进度" + rq.progress);
            yield return null;
        }
        texture = rq.asset as Texture;
    }

    // 测试加载的资源--屏幕上绘制图片
    private void OnGUI()
    {
        if (texture != null)
        {
            GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), texture);
        }
        
    }
}

  • 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

5. 提取异步加载为单例类

现在需要使用一个异步加载资源的单例类, 其他类中可以直接调用该方法实现加载资源,不用手动写回调函数或者自己开协程加载资源.

知识点: 单例 + 异步加载 + 协程 + 委托/事件

单例类的基本思路:

  1. 传入要加载的资源的名称/路径,以及资源的类型
  2. 利用协程加载资源
  3. 资源加载好了要转换为对应的类型
  4. 转化好的资源需要返回给调用的地方
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

public class ResourceLoadManager : MonoBehaviour
{
    // 单例异步加载数据管理器--给外部一个方法用于加载资源

    // private static ResourceLoadManager instance = new ResourceLoadManager();
    private static ResourceLoadManager instance;
	// 单例部分(继承自MonoBehaviour和不继承的)
    private ResourceLoadManager() { }
    public static ResourceLoadManager Instance 
    {
        get
        {
            return instance;
        }
    }
    private void Awake() // 继承自MonoBehaviour的类,需要使用Awake来初始化数据
    {
        instance = this;
    }

    // 普通异步加载 + 回调函数(用来资源加载完毕时候的逻辑,赋值之类的)
    public void LoadResourceAsynchionzed<T>(string sourceName, UnityAction<T> callBack) where T : Object
    {
        // 加载资源
        ResourceRequest rq = Resources.LoadAsync<T>(sourceName);
        // 加载完毕调用回调函数
        rq.completed += (a) => // 这里的a实际上是AsyncOperation的实例 拉姆达函数
        {
            // 调用外部的回调函数 -- 转换资源
            callBack((a as ResourceRequest).asset as T);
            // 将加载好的资源通过外部回调函数返回
            Debug.Log("资源转换成功,并已返回给对象");
        };
    }
    
    // 使用协程加载
    public void LoadResourceAsynchionzedCoroutine<T>(string sourceName, UnityAction<T> callBack) where T : Object
    {
        // 开启协程
        StartCoroutine(LoadSource<T>(sourceName, callBack));
    }

    // 协程
    IEnumerator LoadSource<T>(string sourceName, UnityAction<T> callBack) where T: Object
    {
        // 加载资源中
        ResourceRequest rq = Resources.LoadAsync<T>(sourceName);
        yield return rq;
        // 资源加载好了--转换资源
        callBack(rq.asset as T);
    }
}

  • 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

在需要加载资源的地方调用单例中的加载资源的方法即可

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LoadResourcesTest : MonoBehaviour
{
    private Texture texture; // 图片资源

    private void Start()
    {
        // 调用加载函数 -- 拉姆达表达式
        /*        ResourceLoadManager.Instance.LoadResourceAsynchionzed<Texture>("Pictures/Picture", (obj) =>
                {
                    texture = obj;
                });*/

        // 普通单例异步加载 -- 加载图片资源
        // ResourceLoadManager.Instance.LoadResourceAsynchionzed<Texture>("Pictures/Picture", OnpictureLoaded);
        // 协程单例异步加载-- 加载图片资源
        ResourceLoadManager.Instance.LoadResourceAsynchionzedCoroutine<Texture>("Pictures/Picture", OnPictureLoaded);
    }

    private void OnPictureLoaded(Texture loadedTexture)
    {
        texture = loadedTexture;
    }

    // 测试
    private void OnGUI()
    {
        if (texture != null)
        {
            GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), texture);
        }
    }
}

  • 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

6. 注意事项

  • 异步加载时应确保资源加载完成后再进行操作。
  • 注意资源的卸载,避免内存泄漏。

7. 结论

异步加载资源是Unity游戏开发中的重要技巧,能够显著提升游戏性能和用户体验。开发者应根据项目需求选择合适的异步加载方法。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/969346
推荐阅读
相关标签
  

闽ICP备14008679号