3、Unity【基础】Resources资源场景动态加载

news2024/11/15 21:56:04

在这里插入图片描述

文章目录

  • 一、Resources资源动态加载
    • 1、Unity中特殊文件夹
      • 1、工程路径获取
      • 2、Resources资源文件夹
      • 3、StreamingAssets流动资源文件夹
      • 4、persistentDataPath持久数据文件夹
      • 5、Plugins插件文件夹
      • 6、Editor编辑器文件夹
      • 7、默认资源文件夹StandardAssets
    • 2、Resources同步加载
      • 1、Resources资源动态加载的作用
      • 2、常用资源类型
      • 3、资源同步加载【普通方法】
      • 4、资源同步加载【泛型方法】
    • 3、Resources异步加载
      • 1、Resources异步加载概念
      • 2、Resources异步加载方法
      • 思考 封装资源异步加载管理器
    • 4、Resources卸载资源
      • 1、Resources重复加载资源与内存
      • 2、如何手动释放掉缓存中的资源
  • 二、场景异步加载
    • 1、场景同步切换
    • 2、场景异步切换
      • 1、通过事件回调函数异步加载
      • 2、通过协程异步加载
      • 3、场景异步加载总结
      • 思考 封装场景管理器

一、Resources资源动态加载

1、Unity中特殊文件夹

1、工程路径获取

Application.dataPath //开发使用,打包后无效

2、Resources资源文件夹

路径获取:一般不获取
只能使用Resources相关API进行加载
可以用工程路径拼接获取路径
    print(Application.dataPath+"/Resources");
注意:
需要我们自己创建
作用:
资源文件夹
1.需要通过Resources相关API动态加载的资源需要放在其中
2.该文件夹下所有文件都会被打包
3.打包时Unity会对其压缩加密
4.该文件夹打包后只读只能通过Resources相关API加载

3、StreamingAssets流动资源文件夹

路径获取
	print(Application.streamingAssetsPath);
注意:
需要我们自已创建
作用:
流文件夹
1.打包出去不会被压缩励密,可以任由我们门摆布
2.移动平台只读,PC平台可读可写
3.可以放入一些需要自定义动态加载的初始资源

4、persistentDataPath持久数据文件夹

路径获取
	print(Application.persistentDataPath);
注意:
不需要我们自己创建
作用:
固定数据文件夹
1.所有平台都可读写
2.一般用于放置动态下载或者动态创建的文件,游戏中创建或者获取的文件都放在其中

5、Plugins插件文件夹

路径获取般不获取
注意:
需要我们自己创建
作用:
插件文件夹
不同平台的插件相关文件放在其中
比如放入Ios和Android平台的工具

6、Editor编辑器文件夹

路径获取:一般不获取
如果硬要获取可以用工程路径拼接
注意:
需要我们自己创建
作用:
编辑器文件夹
1.开发Unity编辑器时,编辑器相关脚本放在该文件夹中
2.该文件夹中内容不会被打包出去

7、默认资源文件夹StandardAssets

路劲获取:一般不获取
注意:
需要我们自己创建
作用:
默认资源文件夹
一般Unity自带资源都放在这个文件夹下
代码和资源优先被编译

2、Resources同步加载

1、Resources资源动态加载的作用

1.通过代码动态加载Resources文件夹下指定路径资源
2.避免繁锁的拖曳操作

2、常用资源类型

1.预设体对象 Gameobject
2.音效文件 AudioClip
3.文本文件 TextAsset
4.图片文件 Texture
5.其它类型 需要什么用什么类型
注意:
预设体对象加载需要实例化
其它资源加载一般直接用

3、资源同步加载【普通方法】

一个工程可以有多个Resources文件夹,打包时会自动整合在一起
    
1.预设体对象 想要创建在场景上【实例化】
	第一步:要去加载设体的资源文件(本质上就是加载配置数据在内存中)
    	Object obj = Resources.Load("Cube");
	第二步:如果想要在场景创建预设体一定是加载配置文件过后然后实例化
        Instantiate(obj);

2.音效资源
    public AudioSource audioS;
    第一步:加载数据
    	Object obj = Resources.Load("Music/BkMusic");
    第二步:使用数据,不需要实例化音效切片,只需要把数据赋值到正确的脚本上即可
    	audioS.clip = obj as AudioClip;
		audioS.Play();

3.文本资源
文本资源支持的格式
.txt.xml.bytes.json.html.csv
    TextAsset ta = Resources.Load("Txt/Test")as TextAsset;
文本内容
    print(ta.text);
字节数据组
    print(ta.bytes);

4.图片
    private Texture tex;
        tex = Resources.Load("Tex/TestJPG") as Texture;
	private void OnGUI(){
        GUI.DrawTexture(new Rect(0, 0,100, 100),tex);
    }
		
5.其它类型 需要什么类型就用什么类型就行
    
6.问题:资源同名怎么办
    Resources.Load加载同名资源时,无法准确载出你想要的内容
    可以使用另外的API
    1.加载指定类型的资源
    	tex = Resources.Load("Tex/TestJPG",typeof(Texture)) as Texture;
		ta = Resources.Load("Tex/TestJPG",typeof(TextAsset)) as TextAsset;
    2.加载指定名学的所有资源
        Object[] objs = Resources.LoadAll("Tex/TestJPG")
        foreach (Object item in objs){
            if(itemisTexture){}
            else if(item is TextAsset){}
        }

4、资源同步加载【泛型方法】

TextAsset ta = Resources.Load<TextAsset>("Tex/TestJPG");
tex = Resources.Load<Texture>("Tex/TestJPG");
例:
    bullet = Resources.Load<GameObject>("bullet"); //每次加载不会浪费内存,会消耗性能

3、Resources异步加载

1、Resources异步加载概念

在同步加载中
如果加载过大的资源可能会造成程序卡顿
卡顿的原因就是从硬盘上把数据读取到内存中是需要进行计算的
越大的资源耗时越长,就会造成掉顿卡顿
    
Resources异步加载就是内部新开一个线程进行资源加载不会造成主线程卡顿

2、Resources异步加载方法

异步加载不能马上得到加载的资源,至少要等一帧
1、通过【异步加载】中的完成事件监听,使用加载的资源
    private Texture tex;

    private void LoadOver(AsyncOperation ao){
        print("加载完成");
        print(Time.frameCount); //测试查看帧
        //加载完成后使用asset,是资源对象
        tex = (ao as ResourceRequest).asset as Texture;
	}	
	void Start(){
        //Unity在内部就会去开一个线程进行资源下载
        //LoadAsync方法的返回值ResourceRequest里的asset;
        //ResourceRequest继承的AsyncOperation类有completed事件
        ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
        //马上进行一个资源下载结束的一个事件函数监听
        rq.completed += LoadOver;
        print(Time.frameCount);
    }
    private void OnGUI()
    {
        if(tex!= null)
            GUI.DrawTexture(new Rect(0, 0, 100, 100), tex);

    }
		

2、通过【协程】使用加载的资源
    StartCoroutine(Load());

IEnumerator Load(){
    //【选代器函数】遇到yield return时就会停止执行之后的代码
    //然后【协程协调器】通过得到返回的值去判断下一次执行后面步骤的时间
    ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
    //第一部分
    //Unity自动检测到异步加载资源
    yield return rq;
    
    打印进度
    while(!re.isDone){ //是否结束
        print(re.priority); //priority进度
        yield return null; //测试
    }
    //加载完毕后,Unity自动执行之后代码
    tex = rq.asset as Texture;
}
线程加载和协程异步加载【比较】
1.完成事件监听异步加载
写法简单
但只能在资源加载结束后进行处理
“线性加载”

2.协程异步加载
好处:可以在协程中处理复杂逻辑,比如同时加载【多】个资源,比如进度条更新
坏处:写法稍麻烦
“并行加载” 
    
思考:
理解为什么异步加载不能马上加载结束,为什么至少要等1顿
理解协程异步加载的原理

思考 封装资源异步加载管理器

请写一个简单的资源管理器:
提供统一的方法给外部用于资源异步加载,
外部可以传入委托用于当资源加载结束时使用资源

ResourcesMgr

using UnityEngine;
using UnityEngine.Events;

public class ResourcesMgr
{
    private static ResourcesMgr instance = new ResourcesMgr();

    public static ResourcesMgr Instance => instance;
    private ResourcesMgr(){}
    /// <summary>
    /// 异步加载资源
    /// </summary>
    /// <param name="name">函数名</param>
    /// <param name="callBack">回调函数</param>
    public void AsyncLoadResources<T>(string name, UnityAction<T> callBack) where T : Object
    {
        ResourceRequest resReq = Resources.LoadAsync<T>(name);
        resReq.completed += (finish) =>
        {
            //参数finish是completed的值,事件completed是ResourceRequest的父类,所以:
            //资源对象(finish as ResourceRequest).asset as T
            callBack((finish as ResourceRequest).asset as T);
        };
    }

}

Test_ResMgr

using UnityEngine;

public class Test_ResMgr : MonoBehaviour
{
    private Texture tex;
    void Start()
    {
        //封装前代码
        ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
        rq.completed += (v) =>
        {
            tex = (v as ResourceRequest).asset as Texture;
        };
        //封装后代码
        ResourcesMgr.Instance.AsyncLoadResources<Texture>("Tex/TestJPG", (obj) => { tex = obj; });
    }
    private void OnGUI()
    {
        if (tex != null) //避免异步加载有可能为空
            GUI.DrawTexture(new Rect(0, 0, 200, 100), tex);
    }
}

4、Resources卸载资源

1、Resources重复加载资源与内存

其实Resources加载一次资源过后
该资源就一直存放在内存中【作为缓存】
第二次加载时发现缓存中存在该资源会直接取出来进行使用
所以多次重复加载不会浪费内存
但是会浪费性能(每次加载都会去查找取出,始终伴随一些性能消耗)

2、如何手动释放掉缓存中的资源

1.卸载指定资源
Resources.UnloadAsset方法
注意
该方法不能释放Gameobiect对象因为它会用于实例化对象
它只能用于一些不需要实例化的内容比如图片和音效文本等
一般情况下很少单独使用它

2.卸载未使用的资源
注意:
一般在过场景时和GC一起使用
    Resources.UnloadUnusedAssets(); 
    GC.Collect();

二、场景异步加载

1、场景同步切换

SceneManager.LoadScene("Test") //在Build Settings添加切换场景
场景同步切换的缺点
在切换场景时
Unity会删除当前场景上所有对象,并且去加载下一个场景的相关信息
如果当前场景对象过多或者下一个场景对象过多,这个过程会非常的耗时、卡顿

2、场景异步切换

1、通过事件回调函数异步加载

场景异步加载和资源异步加载几乎一致,有两种方式
1.通过事件回调函数异步加载
	SceneManager.LoadSceneAsync("Test");

void Start()
{
    AsyncOperation ao = SceneManager.LoadSceneAsync("Test");
    //异步加载完成后,使用逻辑
    ao.completed += (a) =>
    {
        print("加载完成");
    };

    ao.completed += LoadOver;
}
private void LoadOver(AsyncOperation ao)
{
    print("LoadOver");
}

2、通过协程异步加载

2.通过协程异步加载
需要注意的是:加载场景会把当前场景上没有特别处理的对象都删除了
所以协程中的部分逻辑可能是执行不了的
解决思路
让处理场景加载的脚本依附的对象,过场景时不被移除
void Start()
{
    DontDestroyOnLoad(gameObject); //挂载此脚本的对象过场景时不被移除
    StartCoroutine(LoadScene("Test"));
}

IEnumerator LoadScene(string name)
{
    ///第一步:
    //异步加载场景
    AsyncOperation ao = SceneManager.LoadSceneAsync(name);
    //Unity内部的协程协调器发现是异步加载类型的返回对象那么就会
    //等待异步加载结束后会续执行选代器函数中后面的步骤
    print("异步加载中");
    //协程的好处是异步加载场景时我可以在加载的同时做一些别的逻辑
    yield return ao;
    //第二步骤:
    print("异步加载后");
    //比如我们门可以在异步加载过程中去更新进度条
    第一种 就是利用场景异步加载的进度去更新但是不是特别准确一般也不会直接用
    while(!ao.isDone)
    {
        print(ao.progress);
        yield return null;
    } 
    //离开循环后就会认为场景加载结束,可以把进度条顶满然后隐藏进度条

    第二种 就是根据你游戏的规则自己定义进度条变化的条件
     //场景加载结束更新20%进度
     //接着去加载场景中的其它信息
     //比如动态加载怪物
     //这时进度条再更新20%
     //动态加载场景模型
     //这时就认为加载结束了100%进度条
     //隐藏进度条
}

3、场景异步加载总结

场景异步加载和资源异步加载一样有两种方式
	1.通过事件回调函数 2.协程异步加载
	
也们的优缺点表现和资源异步加载也是一样的
1.事件回调函数
    优点:写法简单,逻辑清晰
    缺点:只能加载完场景做一些事情不能再加载过程中处理逻辑
2.协程异步加载
    优点:可以在加载过程中处理逻辑,比如进度条更新等
    缺点:写法较为麻烦,要通过协程

思考 封装场景管理器

请写一个简单的场景管理器,
提供统一的方法给外部用于场景异步切换
外部可以传入委托用于当异步切换结束时执行某些逻辑

SceneMgr

using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

public class SceneMgr
{
    private static SceneMgr instance;
    public static SceneMgr Instance => instance;
    public SceneMgr(){}
    public void LoadScene(string name, UnityAction action)
    {
        AsyncOperation ao = SceneManager.LoadSceneAsync(name);
        //通过lambda表达式包裹一层,在内部直接调用外部传入的委托即可
        ao.completed += (a) => { action(); };
    }
}

Test_Scene

using UnityEngine;

public class Test_Scene : MonoBehaviour
{
    void Start()
    {
        SceneMgr.Instance.LoadScene("Test", () => { print("加载完成"); });
    }
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Auto-Editor

文章目录 一、关于 Auto-Editor安装系统兼容性版权 二、切割自动切割的方法看看自动编辑器删掉了什么 三、导出到编辑器命名时间线按 Clip 分割 四、手工编辑五、更多的选择 一、关于 Auto-Editor github : https://github.com/WyattBlue/auto-editor (2.8k star – 2408)主页…

ubuntu 20.04系统安装pytorch

1.1 安装gcc 安装cuda之前&#xff0c;首先应该安装gcc&#xff0c;安装cuda需要用到gcc&#xff0c;否则报错。可以先使用下方指令在终端查看是否已经安装gcc。 gcc --version 如果终端打印如下则说明已经安装。 如果显示“找不到命令 “gcc”......”使用下方指令安装 su…

阅读笔记5:董超底层视觉之美|时空的交错与融合——论视频超分辨率

原文链接&#xff1a;https://mp.weixin.qq.com/s/pmJ56Y0-dbIlYbHbJyrfAA 1. 多帧超分和时空超分 视频超分的本质就是多帧超分&#xff0c;多帧超分的历史远早于视频超分。 在早期&#xff0c;Super Resolution专指多帧超分&#xff0c;因为只有多帧超分才能补充进入真实的信…

Golang | Leetcode Golang题解之第368题最大整除子集

题目&#xff1a; 题解&#xff1a; func largestDivisibleSubset(nums []int) (res []int) {sort.Ints(nums)// 第 1 步&#xff1a;动态规划找出最大子集的个数、最大子集中的最大整数n : len(nums)dp : make([]int, n)for i : range dp {dp[i] 1}maxSize, maxVal : 1, 1fo…

对讲模块升级的重要性-OTA空中升级与串口升级

在现代通信设备的设计中&#xff0c;灵活的升级能力已成为评估模块性能的重要标准。无论是在开发过程中&#xff0c;还是在产品的生命周期内&#xff0c;支持OTA和串口升级的模块可以极大地提高设备的可维护性和适应性。 SA618F30&#xff0c;作为一款高性价比、高集成度的大功…

SSRF 302跳转攻击redis写入ssh公钥实现远程登录

目录 SSRF漏洞 SSRF攻击Redis 302跳转 漏洞复现&#xff1a; index.html: index.php: 攻击步骤&#xff1a; 1.生成ssh公钥数据&#xff1a; 2.用SSH公钥数据伪造Redis数据&#xff1a; 3.在自己的服务器上写302跳转&#xff1a; 4.最后尝试在.ssh目录下登录&#…

Golang | Leetcode Golang题解之第371题两整数之和

题目&#xff1a; 题解&#xff1a; func getSum(a, b int) int {for b ! 0 {carry : uint(a&b) << 1a ^ bb int(carry)}return a }

MySQL主从复制之GTID模式

目录 1 MySQL 主从复制 GTID 模式介绍 2 传统复制模式与GTID复制模式的区别 3 GTID模式核心参数 4 GTID 实现自动复制原理 4.1 GTID基本概念 4.2 GTID复制流程 5 GTID 实现自动定位 5.1 配置 my.cnf 5.2 配置 SLAVE 实现自动定位 5.3 测试 6 GTID 模式 故障转移的方法流程 6.1…

如何使用ssm实现宠物领养系统+vue

TOC ssm103宠物领养系统vue 课题背景 在当今的社会&#xff0c;可以说是信息技术的发展时代&#xff0c;在社会的方方面面无不涉及到各种信息的处理。信息是人们对客观世界的具体描述&#xff0c;是人们进行交流与联系的重要途径。人类社会就处在一个对信息进行有效合理的加…

mysql数据库----简单认识库的操作

目录 1.区分概念 2.什么是数据库 3.数据库的创建和销毁 4.数据库编码初识 5.查询系统默认编码配置 6.两个查询编码表的指令 7.创建指定编码的数据库 8.不同编码的区别 第一个编码方式&#xff1a; 第二个编码方式&#xff1a; 查询结果说明&#xff1a; 9.数据库的增…

QT Quick QML 网络助手——TCP客户端

GitHub 源码: QmlLearningPro &#xff0c;选择子工程 Nettools.pro QML 其它文章请点击这里: QT QUICK QML 学习笔记 ● 运行效果&#xff1a; 左侧为常用的网络调试工具&#xff0c;右侧为本项目 UI 效果&#xff0c;前端使用 QML &#xff0c;后端使用C &#xff…

ArkTs之:数据懒加载——LazyForEach的用法

官方描述 LazyForEach从提供的数据源中按需迭代数据&#xff0c;并在每次迭代过程中创建相应的组件。当在滚动容器中使用了LazyForEach&#xff0c;框架会根据滚动容器可视区域按需创建组件&#xff0c;当组件滑出可视区域外时&#xff0c;框架会进行组件销毁回收以降低内存占…

我在某日重新下载了idea

# 1 Maven设置 2 字体样式,字体颜色 3 插件 1,fitten code和通义灵码 2,one dark theme主题 3,mybatisX 4,Rainbow Brackets 5,Key Promoter X 设置 自动导入包

Ps:首选项 - 常规

Ps菜单&#xff1a;编辑/首选项 Edit/Preferences 快捷键&#xff1a;Ctrl K Photoshop 首选项中的“常规” General选项卡主要用于调整 Photoshop 的整体工作行为和用户体验。这些设置让用户可以根据个人习惯和工作流程定制软件的响应方式和界面布局&#xff0c;从而提高工作…

下载的word中的mathtype公式双击无法打开编辑器

原因分析&#xff1a; 该word中的此公式不是通过word内置的mathtype插入公式的&#xff0c;而是从mathtype编辑器中复制粘贴到word中的。 后者的方式当被其他人下载接收后&#xff0c;无法修改此公式&#xff0c;而且该公式也不能被其他人复制&#xff0c;会报错如下&#xff…

GPT-4o System Card is released

GPT-4o System Card is released, including red teaming, frontier risk evaluations, and other key practices for industrial-strength Large Language Models. https://openai.com/index/gpt-4o-system-card/ 报告链接 企业级生成式人工智能LLM大模型技术、算法及案例实战…

5G毫米波测试助力突破高频段设备局限,实现高效外场测试

作者介绍 一、方案背景 随着业务对带宽需求的不断增加&#xff0c;通信频谱不断向更高频谱延伸&#xff0c;5G毫米波具有丰富的频率资源&#xff0c;是移动通信技术演进的必然方向。下图是ITU的WRC-19会议发布的目前5G所占用频段。 从图中可以看出&#xff0c;在5G毫米波测试中…

AgentQ,超越人类的人工智能代理

MultiOn 宣布推出一款新代理AgentQ&#xff0c;这是一款令人惊叹的产品&#xff0c;它整合了我最近一直在讨论的大部分内容&#xff1a;将 LLM 与搜索相结合。 但这个经纪人很特殊。 与其他代理不同的是&#xff0c;由于巧妙地使用了对齐技术&#xff0c;该代理可以从好的和坏的…

redis | 认识非关系数据库Redis的位图数据类型

Redis 非关 kv型 位图常用命令应用场景python操作位图 位图 位图不是真正的数据类型&#xff0c;它是定义在字符串类型中 01100001 97 61 a 01100010 98 62 b 一个字符串类型的值最多能存储512M字节的内容 位上限&#xff1a;2^32 常用命令 SETBIT \x : 16进制 没有key值 GE…

npm 设置代理

目录 前言 一、查看npm配置 二、设置代理 三、删除代理 四、代理认证 往期回顾 前言 在使用npm时&#xff0c;如果您处于需要使用代理的网络环境中&#xff0c;您可以通过配置npm来设置代理。 一、查看npm配置 npm config list或者单独查看 npm config get proxynpm co…