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);
            }
            
        }
    }
    
    

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);
        }
        
    }
}

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);
    }
}

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

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);
        }
    }
}

6. 注意事项

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

7. 结论

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/767267.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

33.哀家要长脑子了!

憋说了&#xff0c;感觉好不容易长出来的脑子又缩回去了。。。 1.539. 最小时间差 - 力扣&#xff08;LeetCode&#xff09; 把所有时间排好序&#xff0c;然后计算两两之间的分钟差就好&#xff0c;但是要注意加上最后一个和第一个的判断&#xff0c;因为这个时间是按字典序来…

AI研究的主要推动力会是什么?ChatGPT团队研究科学家:算力成本下降

AI 研究发展的主要推动力是什么&#xff1f;在最近的一次演讲中&#xff0c;OpenAI 研究科学家 Hyung Won Chung 给出了自己的答案。 近日&#xff0c;斯坦福大学《CS25: Transformers United V4》课程迎来了一位我们熟悉的技术牛人&#xff1a;Hyung Won Chung。 Chung 是 O…

Hadoop-03-Hadoop集群 免密登录 超详细 3节点公网云 分发脚本 踩坑笔记 SSH免密 服务互通 集群搭建 开启ROOT

章节内容 上一节完成&#xff1a; HDFS集群XML的配置MapReduce集群XML的配置Yarn集群XML的配置统一权限DNS统一配置 背景介绍 这里是三台公网云服务器&#xff0c;每台 2C4G&#xff0c;搭建一个Hadoop的学习环境&#xff0c;供我学习。 之前已经在 VM 虚拟机上搭建过一次&…

Spring容器生命周期中如前置运行程序和后置运行程序

在Spring容器加入一个实现了BeanPostProcessor接口bean实例&#xff0c;重写postProcessBeforeInitialization、postProcessAfterInitialization方法&#xff0c;在方法里面写具体的实现&#xff0c;从而达到Spring容器在初如化前或销毁时执行预定的程序&#xff0c;方法如下&a…

深入浅出:npm常用命令详解与实践【保姆级教程】

大家好,我是CodeQi! 在我刚开始学习前端开发的时候,有一件事情让我特别头疼:管理和安装各种各样的依赖包。 那时候,我还不知道 npm 的存在,手动下载和管理这些库简直是噩梦。 后来,我终于接触到了 npm(Node Package Manager),它不仅帮我解决了依赖管理问题,还让我…

解决Visual Studio 一直弹出管理员身份运行问题(win10/11解决办法)

不知道大家是否有遇到这个问题 解决办法也很简单 找到启动文件 如果是快捷方式就继续打开文件位置 找到这个程序启动项 右键 选择 兼容性疑难解答&#xff08;win11 则需要 按住 shift 右键&#xff09; win10 解决办法 这样操作完后就可以了 win11解决办法按以下选择就行

深入理解策略梯度算法

策略梯度&#xff08;Policy Gradient&#xff09;算法是强化学习中的一种重要方法&#xff0c;通过优化策略以获得最大回报。本文将详细介绍策略梯度算法的基本原理&#xff0c;推导其数学公式&#xff0c;并提供具体的例子来指导其实现。 策略梯度算法的基本概念 在强化学习…

AI大模型时代来临:企业如何抢占先机?

AI大模型时代来临:企业如何抢占先机? 2023年,被誉为大模型元年,AI大模型的发展如同一股不可阻挡的潮流,正迅速改变着我们的工作和生活方式。从金融到医疗,从教育到制造业,AI大模型正以其强大的生成能力和智能分析,重塑着行业的未来。 智能化:企业核心能力的转变 企…

【CUDA】 归约 Reduction

Reduction Reduction算法从一组数值中产生单个数值。这个单个数值可以是所有元素中的总和、最大值、最小值等。 图1展示了一个求和Reduction的例子。 图1 线程层次结构 在Reduction算法中&#xff0c;线程的常见组织方式是为每个元素使用一个线程。下面将展示利用许多不同方…

AI-算力集群通往AGI

背景&#xff1a; 自GPT-4发布以来&#xff0c;全球AI能力的发展势头有放缓的迹象。 但这并不意味着Scaling Law失效&#xff0c;也不是因为训练数据不够&#xff0c;而是结结实实的遇到了算力瓶颈。 具体来说&#xff0c;GPT-4的训练算力约2e25 FLOP&#xff0c;近期发布的几个…

双曲方程初值问题的差分逼近(迎风格式)

稳定性: 数值例子 例一 例二 代码 % function chap4_hyperbolic_1st0rder_1D % test the upwind scheme for 1D hyperbolic equation % u_t + a*u_x = 0,0<x<L,O<t<T, % u(x,0) = |x-1|,0<X<L, % u(0,t) = 1% foundate = 2015-4-22’; % chgedate = 202…

刷代码随想录有感(124):动态规划——最长公共子序列

题干&#xff1a; 代码&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {vector<vector<int>>dp(nums1.size() 1, vector<int>(nums2.size() 1, 0));int res 0;for(int i 1; i <…

买华为智驾,晚了肯定要后悔

文 | AUTO芯球 作者 | 雷慢 晚了就来不及了&#xff01; 你买华为系的车&#xff0c;薅羊毛真的要趁早。 华为ADS2.0高阶智驾正在慢慢恢复原价&#xff0c; 你看啊&#xff0c;就在昨天&#xff0c;华为宣布ADS智驾优惠后价格调到3万元&#xff0c; 只有6000元的优惠了。…

153. 寻找旋转排序数组中的最小值(中等)

153. 寻找旋转排序数组中的最小值 1. 题目描述2.详细题解3.代码实现3.1 Python3.2 Java 1. 题目描述 题目中转&#xff1a;153. 寻找旋转排序数组中的最小值 2.详细题解 如果不考虑 O ( l o g n ) O(log n) O(logn)的时间复杂度&#xff0c;直接 O ( n ) O(n) O(n)时间复杂…

从百数教学看产品设计:掌握显隐规则,打造极致用户体验

字段显隐规则允许通过一个控件&#xff08;如复选框、单选按钮或下拉菜单&#xff09;来控制其他控件&#xff08;如文本框、日期选择器等&#xff09;和标签页&#xff08;如表单的不同部分&#xff09;的显示或隐藏。 这种规则通常基于用户的选择或满足特定条件来触发&#…

vue3实现echarts——小demo

版本&#xff1a; 效果&#xff1a; 代码&#xff1a; <template><div class"middle-box"><div class"box-title">检验排名TOP10</div><div class"box-echart" id"chart1" :loading"loading1"&…

【Portswigger 学院】路径遍历

路径遍历&#xff08;Path traversal&#xff09;又称目录遍历&#xff08;Directory traversal&#xff09;&#xff0c;允许攻击者通过应用程序读取或写入服务器上的任意文件&#xff0c;例如读取应用程序源代码和数据、凭证和操作系统文件&#xff0c;或写入应用程序所访问或…

API Object设计模式

API测试面临的问题 API测试由于编写简单&#xff0c;以及较高的稳定性&#xff0c;许多公司都以不同工具和框架维护API自动化测试。我们基于seldom框架也积累了几千条自动化用例。 •简单的用例 import seldomclass TestRequest(seldom.TestCase):def test_post_method(self…

GDB 远程调试简介

文章目录 1. 前言2. GDB 远程调试2.1 准备工作2.1.1 准备 客户端 gdb 程序2.1.2 准备 服务端 gdbserver2.1.3 准备 被调试程序 2.2 调试2.2.1 通过网络远程调试2.2.1.1 通过 gdbserver 直接启动程序调试2.2.1.2 通过 gdbserver 挂接到已运行程序调试 2.2.2 通过串口远程调试2.2…