Unity特殊文件夹的作用,资源\场景加载方法,同步和异步

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

public class Lesson16 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 工程路径获取
        //注意 该方式 获取到的路径 一般情况下 只在 编辑模式下使用
        //我们不会在实际发布游戏后 还使用该路径
        //游戏发布过后 该路径就不存在了 
        print(Application.dataPath);
        #endregion

        #region 知识点二 Resources 资源文件夹
        //路径获取:
        //一般不获取
        //只能使用Resources相关API进行加载
        //如果硬要获取 可以用工程路径拼接
        print(Application.dataPath + "/Resources");

        //注意:
        //需要我们自己将创建
        //作用:
        //资源文件夹
        //1-1.需要通过Resources相关API动态加载的资源需要放在其中
        //1-2.该文件夹下所有文件都会被打包出去
        //1-3.打包时Unity会对其压缩加密
        //1-4.该文件夹打包后只读 只能通过Resources相关API加载
        #endregion

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

        #region 知识点四 persistentDataPath 持久数据文件夹
        //路径获取:
        print(Application.persistentDataPath);

        //注意:
        //不需要我们自己将创建
        //作用:
        //固定数据文件夹
        //3-1.所有平台都可读可写,这是很重要的特征,因为上面那两个不是可写的,所以这个就很重要
        //3-2.一般用于放置动态下载或者动态创建的文件,游戏中创建或者获取的文件都放在其中
        #endregion

        #region 知识点五 Plugins 插件文件夹
        //路径获取:
        //一般不获取

        //注意:
        //需要我们自己将创建
        //作用:
        //插件文件夹
        //不同平台的插件相关文件放在其中
        //比如IOS和Android平台
        #endregion

        #region 知识点六 Editor 编辑器文件夹
        //路径获取:
        //一般不获取
        //如果硬要获取 可以用工程路径拼接
        print(Application.dataPath + "/Editor");

        //注意:
        //需要我们自己将创建
        //作用:
        //编辑器文件夹
        //5-1.开发Unity编辑器时,编辑器相关脚本放在该文件夹中
        //5-2.该文件夹中内容不会被打包出去
        #endregion

        #region 知识点七 默认资源文件夹 Standard Assets
        //路劲过去:
        //一般不获取

        //注意:
        //需要我们自己将创建
        //作用:
        //默认资源文件夹
        //一般Unity自带资源都放在这个文件夹下
        //代码和资源优先被编译
        #endregion
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Lesson17 : MonoBehaviour
{
    public AudioSource audioS;

    private Texture tex;

    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 Resources资源动态加载的作用
        //1.通过代码动态加载Resources文件夹下指定路径资源
        //2.避免繁琐的拖曳操作
        #endregion

        #region 知识点二 常用资源类型
        //1.预设体对象——GameObject
        //2.音效文件——AudioClip
        //3.文本文件——TextAsset
        //4.图片文件——Texture
        //5.其它类型——需要什么用什么类型

        //注意:
        //预设体对象加载需要实例化
        //其它资源加载一般直接用
        #endregion

        #region 知识点三 资源同步加载 普通方法
        //在一个工程当中 Resources文件夹 可以有多个 通过API加载时 它会自己去这些同名的Resources文件夹中去找资源
        //打包时 Resources文件夹 里的内容 都会打包在一起

        //1.预设体对象 想要创建在场景上 记住实例化
        // 第一步:要去加载预设体的资源文件(本质上 就是加载 配置数据 在内存中)
        Object obj = Resources.Load("Cube");
        //第二步:如果想要在场景上 创建预设体 一定是加载配置文件过后 然后实例化
        Instantiate(obj);

        // 第一步:要去加载预设体的资源文件(本质上 就是加载 配置数据 在内存中)
        Object obj2 = Resources.Load("Sphere");
        //第二步:如果想要在场景上 创建预设体 一定是加载配置文件过后 然后实例化
        Instantiate(obj2);

        //2.音效资源
        //第一步:就是加载数据
        Object obj3 = Resources.Load("Music/BKMusic");
        //第二步:使用数据 我们不需要实例化 音效切片 我们只需要把数据 赋值到正确的脚本上即可
        audioS.clip = obj3 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.图片
        //tex = Resources.Load("Tex/TestJPG") as Texture;

        //5.其它类型 需要什么类型 就用什么类型就行


        //6.问题:资源同名怎么办
        //Resources.Load加载同名资源时 无法准确加载出你想要的内容

        //可以使用另外的API
        //6-1加载指定类型的资源
        //tex = Resources.Load("Tex/TestJPG", typeof(Texture)) as Texture;

        ta = Resources.Load("Tex/TestJPG", typeof(TextAsset)) as TextAsset;
        //print(ta.text);

        //6-2加载指定名字的所有资源
        Object[] objs = Resources.LoadAll("Tex/TestJPG");
        foreach (Object item in objs)
        {
            if (item is Texture)
            { 

            }
            else if(item is TextAsset)
            {

            }
        }

        #endregion

        #region 知识点四 资源同步加载 泛型方法

        TextAsset ta2 = Resources.Load<TextAsset>("Tex/TestJPG");
        print(ta2.text);

        tex = Resources.Load<Texture>("Tex/TestJPG");

        #endregion

        #region 总结
        //Resources动态加载资源的方法
        //让拓展性更强
        //相对拖曳来说 它更加一劳永逸 更加方便

        //重要知识点:
        //记住API
        //记住一些特定的格式
        //预设体加载出来一定要实例化
        #endregion
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private void OnGUI()
    {
        GUI.DrawTexture(new Rect(0, 0, 100, 100), tex);
    }
}

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

public class Lesson18 : MonoBehaviour
{
    private Texture tex;
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 Resources异步加载是什么?
        //上节课学习的同步加载中
        //如果我们加载过大的资源可能会造成程序卡顿
        //卡顿的原因就是 从硬盘上把数据读取到内存中 是需要进行计算的
        //越大的资源耗时越长,就会造成掉帧卡顿

        //Resources异步加载 就是内部新开一个线程进行资源加载 不会造成主线程卡顿
        //然后外面一直有update去检测有没有这个资源(在其他线程有没有生成成功),有的话就拿这个资源干什么事情
        #endregion

        #region 知识点二 Resources异步加载方法
        //注意:
        //异步加载 不能马上得到加载的资源 至少要等一帧,因为是另外开了一个协程
		
        //1.通过异步加载中的完成事件监听 使用加载的资源
        //这句代码 你可以理解 Unity 在内部 就会去开一个线程进行资源下载
        //ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
        //马上进行一个 资源下载结束 的一个事件函数监听,这里就是添加一个事件,在加载完成的时候他会进行自动的调用
        //rq.completed += LoadOver;
        print(Time.frameCount);

        //这个 刚刚执行了异步加载的 执行代码 资源还没有加载完毕 这样用 是不对的 
        //一定要等加载结束过后 才能使用
        //rq.asset ××××××××××××



        //2.通过协程 使用加载的资源
        StartCoroutine(Load());
        #endregion

        #region 总结
        //1.完成事件监听异步加载
        //好处:写法简单
        //坏处:只能在资源加载结束后 进行处理,例如同时加载三个物体,要是分别写三个加减,那么就要分别判断另外几个是不是已经加载完毕,很麻烦
        //“线性加载”

        //2.协程异步加载
        //好处:可以在协程中处理复杂逻辑,比如同时加载多个资源,比如进度条更新
        //坏处:写法稍麻烦,但是可以在同一个方法内去判断所有的资源的加载情况
        //“并行加载”

        //注意:
        //理解为什么异步加载不能马上加载结束,为什么至少要等1帧
        //理解协程异步加载的原理
        #endregion
    }

    IEnumerator Load()
    {
        //迭代器函数 当遇到yield return时  就会 停止执行之后的代码
        //然后 协程协调器 通过得到 返回的值 去判断 下一次执行后面的步骤 将会是何时
        ResourceRequest rq = Resources.LoadAsync<Texture>("Tex/TestJPG");
        print(Time.frameCount);
        //第一部分
        //Unity 自己知道 该返回值 意味着你在异步加载资源 
        //yield return rq;
        //Unity 会自己判断 该资源是否加载完毕了 加载完毕过后 才会继续执行后面的代码
        print(Time.frameCount);
        
        //判断资源是否加载结束
        while(!rq.isDone)
        {
            //打印当前的 加载进度 
            //该进度 不会特别准确 过渡也不是特别明显
            print(rq.progress);
            yield return null;
        }
        tex = rq.asset as Texture;

        //yield return null;
        第二部分
        //yield return new WaitForSeconds(2f);
        第三部分
    }

    private void LoadOver( AsyncOperation rq)
    {
        print("加载结束");
        //asset 是资源对象 加载完毕过后 就能够得到它
        tex = (rq as ResourceRequest).asset as Texture;
        print(Time.frameCount);
    }

    private void OnGUI()
    {
        if( tex != null)
            GUI.DrawTexture(new Rect(0, 0, 100, 100), tex);
    }
}

实现一个资源异步加载管理器

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

public class ResourcesMgr
{
    //这里为了单例
    private static ResourcesMgr instance  = new ResourcesMgr();
    public static ResourcesMgr Instance => instance;
    //避免外面进行new对象
    private ResourcesMgr()
    {
    }

    public void LoadRes<T>(string name, UnityAction<T> callBack) where T:Object
    {
        //开启异步加载
        ResourceRequest rq = Resources.LoadAsync<T>(name);
        //最简单直接的加载,开启线程
        //匿名函数,这里的a是形参,是资源加载完成后传进来的参数被a接收,
        rq.completed += (a) =>
        {
            //直接得到 传入的 对象 通过它得到资源内容 然后转换成对应类型 传出去 外面不需要转换 直接使用
            callBack((a as ResourceRequest).asset as T);
        };
    }
}

卸载资源


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

public class Lesson19 : MonoBehaviour
{
    private Texture tex;
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 Resources重复加载资源会浪费内存吗?
        //其实Resources加载一次资源过后
        //该资源就一直存放在内存中作为缓存
        //第二次加载时发现缓存中存在该资源
        //会直接取出来进行使用
        //所以 多次重复加载不会浪费内存
        //但是 会浪费性能(每次加载都会去查找取出,始终伴随一些性能消耗)

        #endregion

        #region 知识点二 如何手动释放掉缓存中的资源
        //1.卸载指定资源
        //Resources.UnloadAsset 方法
        //注意:
        //该方法 不能释放 GameObject对象 因为它会用于实例化对象
        //它只能用于一些 不需要实例化的内容 比如 图片 和 音效 文本等等
        //一般情况下 我们很少单独使用它
        //GameObject obj = Resources.Load<GameObject>("Cube");
        //即使是没有实例化的 GameObject对象也不能进行卸载
        //Resources.UnloadAsset(obj);

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

        #region 总结
        //Resources.UnloadAsset 卸载指定资源 但是不能卸载GameObject对象
        //Resources.UnloadUnusedAssets 卸载未使用资源 一般过场景时配合GC使用
        #endregion
    }

    // Update is called once per frame
    void Update()
    {
        if(Input.GetKeyDown(KeyCode.Alpha1))
        {
            print("加载资源");
            tex = Resources.Load<Texture>("Tex/TestJPG");
        }
        if(Input.GetKeyDown(KeyCode.Alpha2))
        {
            print("卸载资源");
            Resources.UnloadAsset(tex);
            tex = null;
        }
    }
}

场景加载的方法,同步异步

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

public class Lesson20 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        #region 知识点一 回顾场景同步切换

        //SceneManager.LoadScene("Lesson20Test");

        #region 场景同步切换的缺点
        //在切换场景时
        //Unity会删除当前场景上所有对象
        //并且去加载下一个场景的相关信息
        //如果当前场景 对象过多或者下一个场景对象过多
        //这个过程会非常的耗时 会让玩家感受到卡顿

        //所以异步切换就是来解决该问题的
        #endregion
        #endregion

        #region 知识点二 场景异步切换
        //场景异步加载和资源异步加载 几乎一致 有两种方式

        //1.通过事件回调函数 异步加载
        //AsyncOperation ao = SceneManager.LoadSceneAsync("Lesson20Test");
        //当场景异步加载结束后 就会自动调用该事件函数 我们如果希望在加载结束后 做一些事情 那么久可以在该函数中
        //写处理逻辑
        //ao.completed += (a) =>
        //{
        //    print("加载结束");
        //};

        //ao.completed += LoadOver;


        //2.通过协程异步加载
        //需要注意的是 加载场景会把当前场景上 没有特别处理的对象 都删除了
        //所以 协程中的部分逻辑 可能是执行不了的 
        //解决思路
        //让处理场景加载的脚本依附的对象 过场景时 不被移除

        //该脚本依附的对象 过场景时 不会被 移除
        DontDestroyOnLoad(this.gameObject);

        StartCoroutine(LoadScene("Lesson20Test"));
        #endregion

        #region 总结
        //场景异步加载 和 资源异步加载 一样
        //有两种方式
        //1.通过事件回调函数
        //2.协程异步加载

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

        #endregion
    }

    private void LoadOver(AsyncOperation ao)
    {
        print("LoadOver");
    }


    IEnumerator LoadScene(string name)
    {
        //第一步
        //异步加载场景
        AsyncOperation ao = SceneManager.LoadSceneAsync(name);
        //Unity内部的 协程协调器 发现是异步加载类型的返回对象 那么就会等待
        //等待异步加载结束后 才会继续执行 迭代器函数中后面的步骤
        print("异步加载过程中 打印的信息");
        //协程的好处 是异步加载场景时 我可以在加载的同时 做一些别的逻辑
        //yield return ao;
        //第二步
        print("异步加载结束后 打印的信息");

        //比如 我们可以在异步加载过程中 去更新进度条
        //第一种 就是利用 场景异步加载 的进度 去更新 但是 不是特别准确 一般也不会直接用
        //while(!ao.isDone)
        //{
        //    print(ao.progress);
        //    yield return null;
        //}

        //离开循环后 就会认为场景加载结束
        //可以把进度条顶满 然后 隐藏进度条

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

}

自己封装一个场景管理器

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

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

    public static SceneMgr Instance => instance;

    private SceneMgr() { }

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

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值