unity3d协程加载文件_unity 协程异步加载 - CSDN
  • 工作中遇到一个加载卡顿的问题。 ...并且色卡支持用户自定义上传,但是这里就...以上两个问题加起来会造成明显的卡顿,特别影响客户使用体验,因此,尝试使用协程优化下载和加载。 第一步:定义一个异步加载的类。 ...

    工作中遇到一个加载卡顿的问题。
    公司软件有一个色卡功能,用户可以根据点击的色卡更改背景等相关图片。并且色卡支持用户自定义上传,但是这里就遇到了两个问题。
    1、从服务器下载色卡会造成卡顿。
    2、创建物体并给RawImage赋值的时候会造成卡顿。
    以上两个问题加起来会造成明显的卡顿,特别影响客户使用体验,因此,尝试使用协程优化下载和加载。

    实现过程:
    第一步:创建一个下载数据包类与一个静态帮助类。
    下载数据包类用来存储需要下载数据的url,保存在本地的url。
    静态类用来存储一些各个界面都会用到的数据。

    public class AsyncHttpPackage
    {
        //需要下载资源的地址
        private string url;
        //资源下载到本地的地址
        private string DonwFolder;
        //资源保存在本地的路径
        private string localFolder;
        public string Url
        {
            get { return url; }
            set { url = value; }
        }
        public string LocalFolder
        {
            get { return localFolder; }
            set { localFolder = value; }
        }
        //委托,后续给rawImage会用到
        public Action<string> DownLoaded;
        public AsyncHttpPackage(string url, string localFolder, Action<string>callback)
        {
            this.url = url;
            this.localFolder = localFolder;
            DownLoaded = callback;
        }
    }
    //静态帮助类,用来存储各个界面常用的数据
    public static class StaticHelper
    {
        public static string folderPath = @"D:\Test";
    }
    

    第二步:创建一个单例下载类,用来实现下载相关的功能

    public class AsyncDownSingleton : MonoBehaviour
    {
        private static AsyncDownSingleton _instance;
        public static AsyncDownSingleton Instance
        {
            get
            {
                if (_instance == null)
                {
                    GameObject obj = new GameObject("AsyncSingleton");
                    _instance = obj.AddComponent<AsyncDownSingleton>();
                    DontDestroyOnLoad(obj);
                }
                    return _instance;
            }
        }
        //需要下载数据包的队列
        public Queue<AsyncHttpPackage> listPackage = new Queue<AsyncHttpPackage>();
    
        public void EnterLoadingQueue(AsyncHttpPackage asyncHttpPackage)
        {
            if (!listPackage.Contains(asyncHttpPackage))
                listPackage.Enqueue(asyncHttpPackage);
        }
        //用来初始化文件保存的路径
        public void InitPath()
        {
            if (!Directory.Exists(StaticHelper.folderPath))
            {
                Directory.CreateDirectory(StaticHelper.folderPath);
            }
        }
        public IEnumerator AsyncDownData(AsyncHttpPackage package)
        {
            WWW www = new WWW(package.Url);
            yield return www;
            if(www.isDone)
            {
                package.LocalFolder = package.LocalFolder;
                Debug.Log("下载完成");
                byte[] bytes = www.bytes;
                CreateFile(package.LocalFolder, bytes);
                package.DownLoaded(package.LocalFolder);
            }
        }
        public void OnUpdate()
        {
            if (listPackage.Count > 0)
            {
                var package = listPackage.Dequeue();
                try
                {
                    var filePath = package.LocalFolder;
                    InitPath();
                    if(!File.Exists(filePath))
                    {
                        Debug.Log("文件不存在,开始下载");
                        StartCoroutine(AsyncDownData(package));
                    }
                    else
                    {
                        Debug.Log("文件存在,执行委托");
                        package.DownLoaded(package.LocalFolder);
                    }
                }
                catch (Exception)
                {
                    throw;
                }
            }
        }
        void CreateFile(string path,byte[] bytes)
        {
            File.WriteAllBytes(path,bytes);
        }
        private void Update()
        {
            OnUpdate();
        }
    }
    
    

    第三步:创建一个单例加载图片类,用来实现给rawImage赋值texture的相关功能。

    public class AsyncLoadRawImageSingleton : MonoBehaviour
    {
        private static AsyncLoadRawImageSingleton _instance;
        public static AsyncLoadRawImageSingleton Instacne
        {
            get
            {
                if(_instance==null)
                {
                    GameObject obj = new GameObject("AsyncLoadRawImageSingleton");
                    DontDestroyOnLoad(obj);
                    _instance = obj.AddComponent<AsyncLoadRawImageSingleton>();
                }
                return _instance;
            }
        }
        public void LoadRawImage(RawImage rawImage, string path)
        {
            StartCoroutine(LoadRawSprite(rawImage, path));
        }
        IEnumerator LoadRawSprite(RawImage rawimage, string path)
        {
            WWW www = new WWW(path);
            yield return www;
            if (www.isDone)
            {
                rawimage.texture = www.texture;
            }
        }
    }
    

    实际调用代码:

    public class Test : MonoBehaviour {
        AsyncDownSingleton test;
        void Start () {
            test = AsyncDownSingleton.Instance;
            test.InitPath();
            List<string> downList = CreatUrlList();
            for (int i = 0; i < downList.Count; i++)
            {
                GameObject gameObject = new GameObject(i.ToString());
                gameObject.transform.SetParent(transform);
                gameObject.AddComponent<RawImage>();
                test.EnterLoadingQueue(new AsyncHttpPackage(downList[i], StaticHelper.folderPath+"\\"+i.ToString()+".jpg", (path) => {
                    AsyncLoadRawImageSingleton.Instacne.LoadRawImage(gameObject.GetComponent<RawImage>(), path);
                }));
            }
        }
        //创建需要下载链接的集合
         List<string>CreatUrlList()
        {
            List<string> list = new List<string>();
            string url1 = "https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2164724814,1401845036&fm=26&gp=0.jpg";
            string url2 = "https://ss0.bdstatic.com/94oJfD_bAAcT8t7mm9GUKT-xh_/timg?image&quality=100&size=b4000_4000&sec=1595225204&di=9e00f9e3da7ff7fe0af78d89ac83dd3b&src=http://img.juimg.com/tuku/yulantu/130506/240498-1305060IU666.jpg";
            string url3 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482741&di=2837a39b2fef6bf7a2490c77dfcb03ef&imgtype=0&src=http%3A%2F%2Fattach.bbs.miui.com%2Fforum%2F201312%2F03%2F165620x7cknad7vruvec1z.jpg";
            string url4 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482740&di=1cbb18e268851ac5d3835580cc583689&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1209%2F26%2Fc0%2F14139494_1348624365103.jpg";
            string url5 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482739&di=1615be1823e373873e6ffeef97e4346b&imgtype=0&src=http%3A%2F%2Fimg.ewebweb.com%2Fuploads%2F20191006%2F19%2F1570360737-HvGOTkxnum.jpg";
            string url6 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482738&di=49555cda0bdf10c9826e9ef62b82148d&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2Fb%2F57faf430da5d0.jpg";
            string url7 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482738&di=1968b09642b82d0f0e1b43397e969980&imgtype=0&src=http%3A%2F%2Fwww.jituwang.com%2Fuploads%2Fallimg%2F160405%2F257858-160405000g246.jpg";
            string url8 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237917929&di=51716913142d9db1c88a8a32aa01b681&imgtype=0&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D2845937221%2C3024056832%26fm%3D214%26gp%3D0.jpg";
            string url9 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237482737&di=c68e4a944c13d42e22498bf9b752034a&imgtype=0&src=http%3A%2F%2Fpic1.win4000.com%2Fwallpaper%2F2018-01-03%2F5a4c4270d8799.jpg";
            string url10 = "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1595237950190&di=0732216827e8f0ec36e1ba725d1764db&imgtype=0&src=http%3A%2F%2Fimg2.imgtn.bdimg.com%2Fit%2Fu%3D1753371632%2C983488119%26fm%3D214%26gp%3D0.jpg";
            list.Add(url1);
            list.Add(url2);
            list.Add(url3);
            list.Add(url4);
            list.Add(url5);
            list.Add(url6);
            list.Add(url7);
            list.Add(url8);
            list.Add(url9);
            list.Add(url10);
            return list;
        }
    }
    
    

    逻辑思路整理:
    1、获得需要下载数据的url,工作中一般是后台人员通过接口传递,这里我随便百度了几张图片,将url添加到一个string的List中做演示。
    2、根据传递过来的List创造相应的游戏物体与数据包类,调用数据包类的构造函数对数据包类赋值,然后将数据添加到单例下载类的数据包队列中。
    3、下载类调用自身下载方法,如果已存在,调用加载图片类的协程加载图片方法,如果不存在,调用自身协程下载方法后再调用图片类的协程加载图片方法。

    下载类实现详解:下载方法通过Update调用,判断下载队列的数量是否进行下载操作。
    调用详解:数据包类声明了一个委托,下载类下完数据之后会对这个委托赋值从而调用(传递图片地址然后调用下载类加载图片方法,此处应该是当成事件来用(个人对委托与事件了解的还不够熟悉,后续熟悉了会补充))。
    最终实现效果:
    在这里插入图片描述
    可以看到,在加载图片的时候依旧可以点击Button,如果是同步的话则会卡住,全部执行完才可以进行点击,此处就不做演示了。
    案例Demo
    PS:这里是U3d萌新一只,日常分享工作中遇到的问题以及解决方法。

    2020.8.20 后续更新
    工作中遇到了一件非常操蛋的事情,有一个老项目,登录的时候非常卡,于是查看了一下登录代码。
    发现主要执行了以下几个方法:
    1、UI层初始化方法A。
    2、下载压缩包方法,压缩包里有画图等相关数据(大坑,后续会讲)。
    3、获取需要订单数据的后台接口。
    执行顺序是将A作为回调函数传给3,执行完2之后进行回调。
    即先调用后台接口,获取需要加载订单的常规数据。然后再下载压缩包,压缩包全部下载完成之后再进行UI层的初始化方法A。
    看到这里,小伙伴们估计已经看出来问题了,没错,问题就出现等待压缩包下载完成,调用后台接口拿到数据其实就已经可以可以进行UI层的初始化方法了。
    原本以为是个美差,改下回调方法执行位置不就完成工单了吗,遂改个位置,开始调试。加载速度瞬间加快,点登陆之后就开始加载,结果没想到苦难从此开始。突然间跳出一堆错误,一看全是空引用。好家伙,仔细一看代码,初始化方法A需要调用压缩包里的数据。难怪当初设计的人要先等压缩包下载完成解压然后再初始化。
    那么问题就来了,该如何解决呢?有两种方法:
    1、代码重构,基本不可能,远古代码里面的逻辑鬼知道是啥,而且里面涉及了很多回调(当初找问题的时候回调都快把我人回调傻了),其次太浪费时间,当初写代码的人走了,期间遇到问题也没有办法问。那么就只能使用第二种方法了。(PS:偷偷吐槽一下公司的合作制度,公司前端后端分开,后端的数据可能多个项目部门都在用,经常会这个部门加了一个字段,其他部门没有通知导致调用接口报错)。
    2、使用协程和while循环无限判断本地是否有文件,有则加载并跳出循环,没有则继续循环。
    代码如下:首先改动下载包类,改为只下载文件。

        public AsyncHttpPackage(string url, string localFolder)
        {
            this.url = url;
            this.localFolder = localFolder;
        }
    

    然后改动加载类,新写一个加载方法。

        IEnumerator LoadRawSprite(RawImage rawimage, string path)
        {
            //第一种正常加载方式
            //WWW www = new WWW("file://" + path);
            //yield return www;
            //if (www.isDone && www.error == null)
            //{
            //    rawimage.texture = www.texture;
            //}
            //第二种方式,不知道数据什么时候下载完成。
            WWW www;
            while (true)
            {
                if(File.Exists(path))
                {
                    www = new WWW("file://" + path);
                    yield return www;
                    if (www.isDone && www.error == null)
                    {
                        rawimage.texture = www.texture;
                        yield break;
                    }
                }
                yield return 0;
            }
        }
    

    最后在Test脚本中执行。

    for (int i = 0; i < downList.Count; i++)
            {
                GameObject gameObject = new GameObject(i.ToString());
                gameObject.transform.SetParent(transform);
                gameObject.AddComponent<RawImage>();
                //test.EnterLoadingQueue(new AsyncHttpPackage(downList[i], StaticHelper.folderPath+"\\"+i.ToString()+".jpg", (path) => {
                //    AsyncLoadRawImageSingleton.Instacne.LoadRawImage(gameObject.GetComponent<RawImage>(), path);
                //}));
                //先执行加载的代码
                AsyncLoadRawImageSingleton.Instacne.LoadRawImage(gameObject.GetComponent<RawImage>(), StaticHelper.folderPath + "\\" + i.ToString() + ".jpg");         
            }
            //3秒后执行下载代码
            yield return new WaitForSeconds(3);
            for (int i = 0; i < downList.Count; i++)
                test.EnterLoadingQueue(new AsyncHttpPackage(downList[i], StaticHelper.folderPath + "\\" + i.ToString() + ".jpg"));
    

    如代码所示,先创建了游戏物体,然后调用加载的方法,3秒后才执行下载文件的方法,效果如下:
    在这里插入图片描述
    图片有问号不用管,原因是网络上图片不存在。另外需要注意,用WWW类加载本地文件的时候,需要加上“file://”,第一次加载的时候没加上这个前缀竟然也加载出来了(灵异事件)
    再次总结一下两种协程实现异步的方法:
    第一种:下载数据的时候提供一个额外的回调方法,下载完成的时候调用回调方法加载。
    第二种:先下载图片,想要加载的时候用协程和while循环配合,循环判断本地文件是否存在,存在的时候则加载。(适用于代码结构比较复杂的情况,即偷懒,或许一直判断性能有额外开销?本新手表示这方面不太理解,就不多说了)

    展开全文
  • 公司的项目准备用ab包的形式开发,而加载ab包的功能放在一个没有继承MonoBehaviour的类中,所有在加载ab包的时候,没法用协程来判断ab包是否加载完成,所以我自己用了一种方式来判断; 我用的事异步加载ab包, ...

    公司的项目准备用ab包的形式开发,而加载ab包的功能放在一个没有继承MonoBehaviour的类中,所有在加载ab包的时候,没法用协程来判断ab包是否加载完成,所以我自己用了一种方式来判断;

    我用的事异步加载ab包,

    AssetBundleCreateRequest asset = AssetBundle.LoadFromFileAsync(path);
    

      当然还有其他的加载方式,网上有很多大神都对此有很详细的描述,这里我就不在赘述了,我们可以通过委托 asset.completed,当单个资源包加载完成后,要执行的事;

    void LoadAssetsBundle()
            {
                m_Path = Application.dataPath;
                //获取运行文件的同级目录
                Directory.SetCurrentDirectory(Directory.GetParent(m_Path).FullName);
                m_Path = Directory.GetCurrentDirectory();
                string assetBundlenPath = ConfigManager.Instance().GetAssetBundlePath();
                m_Path += "/"+ assetBundlenPath;
    
                m_AssetsNameList = ConfigManager.ReadAssetBundleName();
    
                string path = m_Path + "/" + m_AssetsNameList[0];
    
                AssetBundleCreateRequest asset = AssetBundle.LoadFromFileAsync(path);
                asset.completed += AssetBundleLoadcompleted;
               
    
            }
    
            private void AssetBundleLoadcompleted(AsyncOperation asset)
            {
                AssetBundleCreateRequest assetBundle = (AssetBundleCreateRequest)asset;
                if (asset == null)
                {
                    Debug.Log(m_AssetsNameList[m_Index] + "加载失败");
                }
                else
                {
                    Debug.Log(m_AssetsNameList[m_Index] + "加载成功");
                    m_AssetBundleList.Add(assetBundle.assetBundle);
                }
    
                if (m_Index < m_AssetsNameList.Count - 1)
                {
                    m_Index++;
                    //LoadAsset(m_Index);
                    string path = m_Path + "/" + m_AssetsNameList[m_Index];
    
                    if (!File.Exists(path))
                    {
                        Debug.Log(m_AssetsNameList[m_Index] + " AssetBundle包文件不存在", LogType.Error);
                        return;
                    }
                    AssetBundleCreateRequest NextAsset = AssetBundle.LoadFromFileAsync(path);
                    NextAsset.completed += AssetBundleLoadcompleted;
                    
                }
                else
                {
                    Debug.Log(m_AssetsNameList.Count + "个资源包全部加载完成");
                    for (int i = 0; i < m_AssetBundleList.Count; i++)
                    {
                        Debug.Log(m_AssetBundleList[i].name);
                    }
                    
                }
            }
    

      上述代码中有些方法是公司项目中自定义的,需要稍加修改。

    新人第一次发帖,如有错误,还望各位大神指出

    转载于:https://www.cnblogs.com/nfengjing/p/10422379.html

    展开全文
  • Unity3D加载外部图片的两种方法

    千次阅读 2015-12-23 12:01:45
    各位朋友大家好,我是秦元培,欢迎大家关注我的博客。最近在做项目的过程中遇到这样的一个需求:玩家可以在游戏过程中进行实时存档,在...首先是截取游戏画面,这个问题大家可以在《Unity3D游戏开发之截屏保存精彩瞬
    各位朋友大家好,我是秦元培,欢迎大家关注我的博客。最近在做项目的过程中遇到这样的一个需求:玩家可以在游戏过程中进行实时存档,在存档过程中会保存当前游戏进度,同时会截取当前游戏画面并加载到游戏存档界面中。当下一次进入游戏的时候,将读取本地存档图片并加载到游戏界面中。这在单机游戏中是特别常见的一种功能,这里主要有两个关键点。首先是截取游戏画面,这个问题大家可以在《Unity3D游戏开发之截屏保存精彩瞬间》这篇文章中找到答案。其次是从本地加载图片,因为这里要保证可读可写,因此传统的Resources.Load()方式和AssetBundle方式均无法实现这样的功能。那么怎样从外部加载图片到游戏中,这就是我们今天要讨论的内容啦。好了,这里介绍两种方法来实现这一目的。

    喜闻乐见的WWW方式  喜闻乐见的WWW方式之所以喜闻乐见,这是因为这是我们最为熟悉的一种,我们都知道通过WWW可以从网络上加载文本、图片、音频等形式的内容,那么通过WWW能否加载本地外部(相对于应用程序)资源呢?答案是肯定的,这是因为WWW可以支持http和file两种协议。我们通常接触到的WWW默认都是指http协议,现在我们来说说file协议,该协议可以用来访问本地资源(绝对路径)。例如我们希望加载文件D:\TestFile\pic001.png这个文件,则此时对应的C#脚本为:
    [AppleScript] 纯文本查看 复制代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    //请求WWW
    WWW www = new WWW("file://D:\\TestFile\\pic001.png);
    yield return www;       
    if(www != null && string.IsNullOrEmpty(www.error))
    {
        //获取Texture
        Texture texture=www.texture;  
        //更多操作...      
    }

    注意到这里出现了yield return结构,这表示这里使用到了协程,因此我们需要付出的代价就是需要在项目中使用StartCoroutine等协程相关的方法来调用这些协程。虽然在Unity3d中使用协程是件简单的事情,可是如果我们随随便便地使用协程而不注意去维护这些协程,那么这些让我们引以为傲的简单代码可能就会变成我们痛苦不堪的无尽深渊。
    亘古不变的传统IO方式  好了,下面我们隆重推出亘古不变的传统IO方式,这种方式相信大家都没有接触过,所以这里将这种方法和大家分享。既然是传统的IO方式,那么无非就是各种IO流的处理啦。好,我们一起来看下面这段代码:
    [AppleScript] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    10
    11
    12
    13
    14
    15
    16
    17
    //创建文件读取流
    FileStream fileStream = new FileStream(screen, FileMode.Open, FileAccess.Read);
    fileStream.Seek(0, SeekOrigin.Begin);
    //创建文件长度缓冲区
    byte[] bytes = new byte[fileStream.Length];
    //读取文件
    fileStream.Read(bytes, 0, (int)fileStream.Length);
    //释放文件读取流
    fileStream.Close();
    fileStream.Dispose();
    fileStream = null;
     
    //创建Texture
    int width=800;
    int height=640;
    Texture2D texture = new Texture2D(width, height);
    texture.LoadImage(bytes);

    可以看到在使用这种方式读取图片文件的时候主要是将图片文件转化为byte[]数组,再利用Texture2D的LoadImage方法转化为Unity3D中的Texture2D。这种方法需要在创建过程中传入图片的大小,在这里我们创建了一张800X640的图片。经过博主的研究发现,这种方式加载外部图片相对于使用WWW加载外部图片效率更高,所以如果大家遇到类似的需求,博主个人推荐大家使用这种方式进行加载。
      到目前为止我们解决了如何从外部加载图片到Unity3D中,现在我们回到最开始的问题,我们从外部读取到这些图片以后需要将它们加载到游戏界面中。比如当我们使用UGUI的时候,UGUI中的Image控件需要一个Sprite来作为它的填充内容,那么此时我们就需要将Texture转化为Sprite.号了,下面我们给出一个简单的例子:
    [AppleScript] 纯文本查看 复制代码
    01
    02
    03
    04
    05
    06
    07
    08
    09
    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
    using UnityEngine;
    using System.Collections;
    using UnityEngine.UI;
    using System.IO;
     
    public class TestLoading : MonoBehaviour
    {
        /// <summary>
        /// Image控件
        /// </summary>
        private Image image;
     
        void Start ()
        {
            image = this.transform.Find("Image").GetComponent<Image>();
     
            //为不同的按钮绑定不同的事件
            this.transform.Find("LoadByWWW").GetComponent<Button>().onClick.AddListener
            (
               delegate(){LoadByWWW();}
            );
     
            this.transform.Find("LoadByIO").GetComponent<Button>().onClick.AddListener
            (
              delegate(){LoadByIO();}
            );
        }
     
        /// <summary>
        /// 以IO方式进行加载
        /// </summary>
        private void LoadByIO()
        {
            double startTime = (double)Time.time;
            //创建文件读取流
            FileStream fileStream = new FileStream("D:\\test.jpg", FileMode.Open, FileAccess.Read);
            fileStream.Seek(0, SeekOrigin.Begin);
            //创建文件长度缓冲区
            byte[] bytes = new byte[fileStream.Length];
            //读取文件
            fileStream.Read(bytes, 0, (int)fileStream.Length);
            //释放文件读取流
            fileStream.Close();
            fileStream.Dispose();
            fileStream = null;
     
            //创建Texture
            int width = 300;
            int height = 372;
            Texture2D texture = new Texture2D(width, height);
            texture.LoadImage(bytes);
     
            //创建Sprite
            Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
            image.sprite = sprite;
     
            startTime=(double)Time.time-startTime;
            Debug.Log("IO加载用时:" + startTime);
        }
     
        /// <summary>
        /// 以WWW方式进行加载
        /// </summary>
        private void LoadByWWW()
        {
            StartCoroutine(Load());
        }
     
        IEnumerator Load()
        {
            double startTime = (double)Time.time;
            //请求WWW
            WWW www = new WWW("file://D:\\test.jpg");
            yield return www;       
            if(www != null && string.IsNullOrEmpty(www.error))
            {
                //获取Texture
                Texture2D texture=www.texture;
     
                //创建Sprite
                Sprite sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height), new Vector2(0.5f, 0.5f));
                image.sprite = sprite;
     
                startTime = (double)Time.time - startTime;
                Debug.Log("WWW加载用时:" + startTime);
            }
        }
    }

    现在我们运行程序可以发现两种方式均可以让图片加载进来,为了对比两种方式在执行效率上的高低,我们在脚本中加入了相关代码,通过对比可以发现使用IO方式加载一张227k的图片需要的时间为0s,而使用WWW方式加载需要0.0185s,因此传统的IO方式具有更高的效率,建议大家在遇到这类问题时尽可能地使用这种方式。好了,今天的内容就是这样啦。
    展开全文
  • 相信大家会经常遇到在游戏中需要WWW从本地或者服务器上获取数据,而我们通常容易会犯下面这种个错误:当数据较少或者网速较好时程序运行正常。... 1 //检测文件是否存在 2 if (!File.Exists(appDBPath...

    相信大家会经常遇到在游戏中需要WWW从本地或者服务器上获取数据,而我们通常容易会犯下面这种个错误:当数据较少或者网速较好时程序运行正常。而当数据较大或者网速不好时程序会出错误。比如卡住。 

    所以我们要使数据完全读完后再进行数据操作。本宝宝曾经在网上找到了貌似可以的代码:

     1         //检测文件是否存在
     2         if (!File.Exists(appDBPath))
     3         {
     4             //如果文件不存在 拷贝数据库
     5             StartCoroutine(CopyDataBase());
     6         }
     7 
     8 
     9    private bool boo = true;
    10     /// <summary>
    11     /// 拷贝数据库
    12     /// </summary>
    13     IEnumerator CopyDataBase()
    14     {
    15 #if UNITY_STANDALONE_WIN || UNITY_EDITOR
    16         //WWW 可以从本地或者服务器上获取数据
    17         WWW loadDB = new WWW(Application.streamingAssetsPath + "/ARPG.db");
    18 #elif UNITY_IPHONE
    19         WWW loadDB = new WWW(Application.dataPath + "/Raw/" + "/ARPG.db");
    20 #elif UNITY_ANDROID
    21         WWW loadDB = new WWW("jar:file://" + Application.dataPath + "!/assets" + "/ARPG.db");
    22 #endif
    23         //返回loadDB
    24         yield return loadDB;
    25         //进行循环判断 假如boo为真 执行
    26         while (boo)
    27         {
    28             //判断是否加载完毕 如果没完进入
    29             if (loadDB.isDone)
    30             {
    31                 //写入
    32                 File.WriteAllBytes(appDBPath, loadDB.bytes);
    33                 boo = false;
    34             }
    35         }
    36     }

    然而宝宝试过后发现并没有什么卵用   代码看起来很有逻辑 但是仔细想想,当在你开启协程后(5),代码会继续向下做,不管你协程里写的天花乱坠,然而和后面的代码毫无关系。

    其实不用这么麻烦,双协程可以很好的解决这个问题:

     IEnumerator Start()
        {
           appDBPath = Application.streamingAssetsPath + "/ARPG.db";//地址
            StartCoroutine(CopyDataBase());
            yield return null;
        }
    
    
        /// <summary>
        /// 拷贝数据库
        /// </summary>
        public IEnumerator CopyDataBase()
        {
    #if UNITY_STANDALONE_WIN || UNITY_EDITOR
            //WWW 可以从本地或者服务器上获取数据
            WWW loadDB = new WWW(Application.streamingAssetsPath + "/ARPG.db");
    #elif UNITY_IPHONE
            WWW loadDB = new WWW(Application.dataPath + "/Raw/" + "/ARPG.db");
    #elif UNITY_ANDROID
            WWW loadDB = new WWW("jar:file://" + Application.dataPath + "!/assets" + "/ARPG.db");
    #endif
            //判断是否完成
            while (loadDB.isDone)
            {
                yield return loadDB;
                File.WriteAllBytes(appDBPath, loadDB.bytes);
            }
        }        

    是不是很简单啊 双协程中只有第二个协程结束后 第一个协程才会继续向下(个人理解 如果那里有错,请前辈们指正哦!)

     

    转载于:https://www.cnblogs.com/redUnity/p/5149884.html

    展开全文
  • 最近在做项目的过程中遇到这样的一个需求:玩家可以在游戏过程中进行实时存档,在存档过程...首先是截取游戏画面,这个问题大家可以在《Unity教程之-Unity3d游戏开发之截屏保存精彩瞬间》这篇文章中找到答案。其次是从
  • Unity3D协程

    2018-07-09 18:43:11
    从而达到“同时的效果”),比较消耗系统资源协程:实现一个任务在不同时间内分段执行,相对游戏来说系统开销不大具体知识:1.什么是协调程序unity协程是一个能暂停执行,暂停后立即返回,直到中断指令完成后继续...
  • Unity3D资源加载Resources

    千次阅读 2019-06-29 14:24:54
    Unity3D资源加载Resources 目录 1、博客介绍 2、内容 3、推送 4、结语 1、博客介绍 本篇博客对资源加载类Resources做一个介绍 2、内容 FindObjectsOfTypeAll 返回一个该类型对象的列表 Load 从...
  • 首先,Unity官方也提到过《我的应用为什么应该使用线程而不是协程?》先说协程协程方法可以一段接一段时间执行,但所有进程仍然由一个主线程完成。 如果一个协程尝试执行耗时的操作,整个应用程序暂时停止。
  • UNITY所谓的异步加载几乎全部是协程,不是线程;MAP3加载时解压非常慢 实践证明,以下东西都是协程,并非线程(thread): 1,WWW 2,AssetBundle.LoadFromFileAsync 3,LoadSceneAsync 其它未经测试 此问题的...
  • 参考博客: ... 什么是协程?(又称协同程序) ...协程不是多线程,它与主线程同时运行,它在主线程运行的同时开启另一段逻辑处理,类似一个子线程单独出来处理一些问题,性能开销较小,,Unity协程会在每帧结...
  • Unity如何使用WWW类和协程完成图片、视频下载播放(一)
  • 最近在做项目的过程中遇到这样的一个需求:玩家可以在游戏过程中进行实时存档,在...首先是截取游戏画面,这个问题大家可以在《Unity3D游戏开发之截屏保存精彩瞬间》这篇文章中找到答案。其次是从本地加载图片,因为这
  • unity3D协程和线程混合

    千次阅读 2014-07-24 23:21:20
    这是我google unity3D一个问题偶然发现的在stackflow上很有趣的帖子: 大意是 要在unity3D上从服务器下载一个zip,并解压到持久化地址.并将其加载到内存中.下面展示了这种用法: IEnumerator LongCoroutine() { ...
  • 今天讲解一下如何使用WWW类和协程完成简单的图片和视频下载播放功能。 一、WWW类 WWW是一个Unity开发中非常常用到的工具类,主要提供一般Http访问的功能,以及动态从网上下载图片、声音、视频、Unity资源等。 注意:...
  • 今天要做一个移动平台的版本控制,先做一个前期的工作,就是从服务器端加载资源,然后读取到本地,再从本地读取资源。这里就以pc平台为例,移动平台也是一样,就是稍微做一点路径上的修改, 下面是不同平台路径的...
  • 但是当我们打包成apk文件,并在手机上面安装并游玩的时候,发现出现问题了,xml文件好像没有加载出来,因为游戏中的对话全部没法正常执行。原来,在安卓环境下不支持XmlDocument.Load(Path)。我们要使用WWW来加载xml...
  • 大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是:blog.csdn.net/qinyuanpei。...作为大家等待博主更新博客的回报,我们今天来说一说Unity3D中的游戏场景异步加载。那么什么是游戏场景异步加载呢?异步
  • 众所周知在Unity3D游戏开发过程中,因为受到游戏容量、平台性能和热更新等诸多因素的限制,我们可能无法将所有的游戏场景打包到项目中然后相对”静态”地加载,那么这个时候就需要我们使用动态加载的方式来将游戏...
  • unity协程与线程同时使用

    千次阅读 2018-06-29 17:55:16
    为什么要在协程中开启线程, 因为很多时候我们是需要线程执行完成后回到主线程的。然后主线程在继续执行后续的操作。首先,Unity官方也提到过《我的应用为什么应该使用线程而不是协程?》先说协程协程方法可以一段...
1 2 3 4 5 ... 20
收藏数 844
精华内容 337
关键字:

unity3d协程加载文件