• unity使用async await异步unitywebrequest 加载 streamingAssets文件,取代 WWW 和 协程


    如果现在你在中文网上查询一些关于加载 streamingAssetsPath 或者是 persistentDataPath 路径下的文件,你能找到的大部分都是让你用 WWW 配合 协程 来实现这一步。

    中文网上此类相关介绍很少。WWW 和 协程 的编写让代码变得臃肿,而协程连返回值都没。要么用大段代码块,或者是注入委托调用。

    unity现在已经支持 .net core 了,并且引入UnityWebRequest

    先上代码,加载本地的图片文件

    
    
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using System.Runtime.CompilerServices;
    using System.Threading.Tasks;
    using UnityEngine;
    using UnityEngine.Networking;

    public static class LoadHelper
    {
    public static async Task<Sprite> LoadSpritePNG(string path)
    {
    var task = LoadAsyncSprite(path, ".png");
    Task<Sprite> t = await Task.WhenAny(task);
    return t.Result;
    }

    public static async Task<Sprite> LoadSpriteJPG(string path)
    {
    var task = LoadAsyncSprite(path, ".jpg");
    Task<Sprite> t = await Task.WhenAny(task);
    return t.Result;
    }

    static async Task<Sprite> LoadAsyncSprite(string url, string end)
    {
    string path = Path.Combine(Application.streamingAssetsPath, url + end);
    var getRequest = UnityWebRequest.Get(path);
    await getRequest.SendWebRequest();
    byte[] imgData = getRequest.downloadHandler.data;
    Texture2D tex = new Texture2D(2, 2);
    tex.LoadImage(imgData);
    Vector2 pivot = new Vector2(0.5f, 0.5f);
    Sprite sprite = Sprite.Create(tex, new Rect(0.0f, 0.0f, tex.width, tex.height), pivot, 100.0f);
    return sprite;
    }

    }

    public static class ExtensionMethods
    {
    public static TaskAwaiter GetAwaiter(this AsyncOperation asyncOp)
    {
    var tcs = new TaskCompletionSource<object>();
    asyncOp.completed += obj => { tcs.SetResult(null); };
    return ((Task)tcs.Task).GetAwaiter();
    }
    }
     

    调用即可

    ---------------------------------------------------------------------------------------分割--------------------------------------------------------------------------------------------------------

    好的那么下面来讲下async await

    让我们看一个简单的例子。给定以下协程:

    public class AsyncExample : MonoBehaviour
    {
        IEnumerator Start()
        {
            Debug.Log("Waiting 1 second...");
            yield return new WaitForSeconds(1.0f);
            Debug.Log("Done!");
        }
    }

    使用async-await的等效方法如下:

    public class AsyncExample : MonoBehaviour
    {
        async void Start()
        {
            Debug.Log("Waiting 1 second...");
            await Task.Delay(TimeSpan.FromSeconds(1));
            Debug.Log("Done!");
        }
    }

    简而言之,Unity协程使用C#对迭代器块的内置支持来实现您提供给StartCoroutine方法的IEnumerator迭代器对象由Unity保存,并且该迭代器对象的每一帧都向前推进以获取由协程产生的新值。然后,Unity会读取您“ yield return”的不同值以触发特殊情况的行为,例如执行嵌套协程(返回另一个IEnumerator时),延迟几秒钟(返回WaitForSeconds类型的实例时)或等到下一帧(返回null时)。

    不幸的是,由于async-await在Unity中是相当新的事实,因此上述对协程的内置支持并不像async-await那样以类似的方式存在。这意味着我们必须自己添加很多这种支持。

    但是,Unity确实为我们提供了一个重要方面。如您在上面的示例中看到的,默认情况下,我们的异步方法将在主unity线程上运行。在非统一C#应用程序中,异步方法通常会自动在单独的线程上运行,这在Unity中会是一个大问题,因为在这种情况下我们将无法始终与Unity API进行交互。没有Unity引擎的支持,我们对异步方法内部的Unity方法/对象的调用有时会失败,因为它们将在单独的线程上执行。在后台,它可以这样工作,因为Unity提供了一个默认的SynchronizationContext,称为UnitySynchronizationContext,它自动收集在每个帧中排队的所有异步代码,并继续在主要unity线程上运行它们。

    事实证明,这足以让我们开始使用async-await!我们只需要一些帮助程序代码就可以使我们做一些有趣的事情,而不仅仅是简单的时间延迟。

    当前,我们没有很多有趣的异步代码可以编写。我们可以调用其他异步方法,并且可以使用Task.Delay,就像上面的示例中一样,但除此之外就不多了。

    作为一个简单的示例,让我们添加直接在TimeSpan上“等待”的功能,而不必总是像上面的示例那样每次都调用Task.Delay。像这样:

    public class AsyncExample : MonoBehaviour
    {
        async void Start()
        {
            await TimeSpan.FromSeconds(1);
        }
    }

    我们需要做的就是为此添加一个自定义的GetAwaiter扩展方法到TimeSpan类中:

    public static class AwaitExtensions
    {
        public static TaskAwaiter GetAwaiter(this TimeSpan timeSpan)
        {
            return Task.Delay(timeSpan).GetAwaiter();
        }
    }

    之所以可行,是因为为了在更新版本的C#中支持“等待”给定的对象,所需要做的就是该对象具有一个名为GetAwaiter的方法,该方法返回一个Awaiter对象。这很棒,因为它允许我们通过使用上述扩展方法来等待我们想要的任何东西,而无需更改实际的TimeSpan类。

    我们也可以使用这种方法来支持等待其他类型的对象,包括Unity用于协程指令的所有类!我们可以使WaitForSeconds,WaitForFixedUpdate,WWW等全部等待,就像它们在协程中可屈服一样。我们还可以向IEnumerator添加GetAwaiter方法以支持等待协程,以允许将异步代码与旧的IEnumerator代码互换。

    ------------------------------------------------------------------------------------------------------------------------------

    此处已经有一些工具类,定义好了一些GetAwaiter

    https://github.com/svermeulen/Unity3dAsyncAwaitUtil/releases

    【使用】

    public class AsyncExample : MonoBehaviour
    {
        public async void Start()
        {
            // Wait one second
            await new WaitForSeconds(1.0f);
     
            // Wait for IEnumerator to complete
            await CustomCoroutineAsync();
     
            await LoadModelAsync();
     
            // You can also get the final yielded value from the coroutine
            var value = (string)(await CustomCoroutineWithReturnValue());
            // value is equal to "asdf" here
     
            // Open notepad and wait for the user to exit
            var returnCode = await Process.Start("notepad.exe");
     
            // Load another scene and wait for it to finish loading
            await SceneManager.LoadSceneAsync("scene2");
        }
     
        async Task LoadModelAsync()
        {
            var assetBundle = await GetAssetBundle("www.my-server.com/myfile");
            var prefab = await assetBundle.LoadAssetAsync<GameObject>("myasset");
            GameObject.Instantiate(prefab);
            assetBundle.Unload(false);
        }
     
        async Task<AssetBundle> GetAssetBundle(string url)
        {
            return (await new WWW(url)).assetBundle
        }
     
        IEnumerator CustomCoroutineAsync()
        {
            yield return new WaitForSeconds(1.0f);
        }
     
        IEnumerator CustomCoroutineWithReturnValue()
        {
            yield return new WaitForSeconds(1.0f);
            yield return "asdf";
        }
    }

    如您所见,像这样使用async await可能非常强大,尤其是当您像上面的LoadModelAsync方法中一样开始组合多个异步方法时。

    请注意,对于返回值的异步方法,我们使用Task的通用版本,并将返回类型作为通用参数传递,就像上面的GetAssetBundle一样。

    还要注意,在大多数情况下,使用上面的WaitForSeconds实际上比我们的TimeSpan扩展方法更可取,因为WaitForSeconds将使用Unity游戏时间,而我们的TimeSpan扩展方法将始终使用实时(因此不受Time.timeScale更改的影响)

    (摘自:http://www.stevevermeulen.com/index.php/blog/)

     视频地址  https://gametorrahod.com/unity-and-async-await/

  • 相关阅读:
    Read-Copy Update Implementation For Non-Cache-Coherent Systems
    10 华电内部文档搜索系统 search04
    10 华电内部文档搜索系统 search05
    lucene4
    10 华电内部文档搜索系统 search01
    01 lucene基础 北风网项目培训 Lucene实践课程 索引
    01 lucene基础 北风网项目培训 Lucene实践课程 系统架构
    01 lucene基础 北风网项目培训 Lucene实践课程 Lucene概述
    第五章 大数据平台与技术 第13讲 NoSQL数据库
    第五章 大数据平台与技术 第12讲 大数据处理平台Spark
  • 原文地址:https://www.cnblogs.com/sanyejun/p/14059723.html
Copyright © 2020-2023  润新知