如果现在你在中文网上查询一些关于加载 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/

unity使用async await异步unitywebrequest 加载 streamingAssets文件,取代 WWW 和 协程的更多相关文章

  1. 页面异步加载javascript文件

    昨天听一同事说的异步加载js文件,可以提高页面加载速度.具体方法如下:(function() {  var ga = document.createElement('script'); ga.type ...

  2. Dojo初探之1:AMD规范,编写符合AMD规范(异步模块加载机制)的模块化JS(其中dojo采用1.11.2版本)

    一.AMD规范探索 1.AMD规范(即异步模块加载机制) 我们在接触js的时候,一般都是通过各种function来定义一些方法,让它们帮我们做一些事情,一个js可以包含很多个js,而这些functio ...

  3. echarts异步数据加载(在下拉框选择事件中异步更新数据)

    接触echarts 大半年了,从不会到熟练也做过不少的图表,隔了一段时间没使用这玩意,好多东西真心容易忘了.在接触echarts这期间也没有总结什么东西,今天我就来总结一下如何在echart中异步加载 ...

  4. 网页性能优化之异步加载js文件

    一个网页的有很多地方可以进行性能优化,比较常见的一种方式就是异步加载js脚本文件.在谈异步加载之前,先来看看浏览器加载js文件的原理. 浏览器加载 JavaScript 脚本,主要通过<scri ...

  5. 异步加载js文件的方法

    # 异步加载js文件 - js的加载默认是同步的,因为js是单线程执行,只能完成一件再执行下一件. - 一些外部引入的js文件可以因为文件太大,在加载资源的过程中会影响dom元素的加载,影响了用户体验 ...

  6. 深入理解协程(四):async/await异步爬虫实战

    本文目录: 同步方式爬取博客标题 async/await异步爬取博客标题 本片为深入理解协程系列文章的补充. 你将会在从本文中了解到:async/await如何运用的实际的爬虫中. 案例 从CSDN上 ...

  7. js动态加载js文件(js异步加载之性能优化篇)

    1.[基本优化] 将所有需要的<script>标签都放在</body>之前,确保脚本执行之前完成页面渲染而不会造成页面堵塞问题,这个大家都懂. 2.[合并JS代码,尽可能少的使 ...

  8. flask+sqlite3+echarts3+ajax 异步数据加载

    结构: /www | |-- /static |....|-- jquery-3.1.1.js |....|-- echarts.js(echarts3是单文件!!) | |-- /templates ...

  9. javascript 异步模块加载 简易实现

    在javascript是没有类似java或其他语言的模块概念的,因此也不可能通过import或using等关键字来引用模块,这样造成了复杂项目中前端代码混乱,变量互相影响等. 因此在复杂项目中引入AM ...

  10. Angularjs 异步模块加载项目模板

    ng-lazy-module-seed(Angularjs 异步模块加载项目模板) 相信做过SPA项目的朋友都遇到过这个问题:页面初始化时需要加载文件太大或太多了,许多文件加载后很可能不会运行到,这是 ...

随机推荐

  1. CANopen TPDO 配置详解:对象 1800h、1A00h 与实践指南

    CANopen TPDO 配置详解:对象 1800h.1A00h 与实践指南 目录 CANopen TPDO 配置详解:对象 1800h.1A00h 与实践指南 目录 引言 TPDO 通讯参数详解 ( ...

  2. 基于libwchnet&Mbedtls实现HTTPS

    引言: 本文将介绍使用CH32V307VCT6以及官方协议栈(libwchnet)搭配Mbedtls作为客户端通过HTTPS访问百度并获取百度首页数据. 一.HTTPS概述与SSL/TSL简介 HTT ...

  3. RPC实战与核心原理之路由策略

    路由策略:怎么让请求按照设定的规则发到不同的节点上 回顾 健康检测在 RPC 中的作用,简单来讲就是帮助调用方应用来管理所有服务提供方的连接,并动态维护每个连接的状态,方便服务调用方在每次发起请求的时 ...

  4. codeup之奖金计算

    codeup c2奖金计算 Description 某企业发放的奖金根据利润提成.利润I低于或等于100000时,奖金可提10%:利润高于100000元,低于200000元(100000<I&l ...

  5. 8086汇编(16位汇编)学习笔记00.DEBUG命令使用解析及范例大全

    转载自:https://bpsend.net/thread-99-1-1.html 启动 Debug,它是可用于测试和调试 MS-DOS 可执行文件的程序. Debug [[drive:][path] ...

  6. 【uni-app】在windows10系统中HBuliderX用iPhone苹果手机进行调试运行详细说明

    测试准备: 1)iphone13  ios18.4.1  和一根可以读取数据的苹果线 2)HBuliderX打开uni-app项目文件(项目图标是正方形内一个U) 3)windows10系统 测试目标 ...

  7. AI 制作游戏美术素材流程分享(程序员方向粗糙版)

    AI 制作游戏美术素材分享(程序员方向粗糙版) 视频讲解: 抖音:https://www.douyin.com/user/self?from_tab_name=main&modal_id=75 ...

  8. 第9.2讲、Tiny Decoder(带 Mask)详解与实战

    自己搭建一个 Tiny Decoder(带 Mask),参考 Transformer Encoder 的结构,并添加 Masked Multi-Head Self-Attention,它是 Decod ...

  9. 万字长文: 仅花7天,利用AI编程神器Cursor 从0到1开发上线个人网站,保姆级教程!

    大家好,我是狂师. 今天我们来分享一下,如何利用AI编程帮助我们开发一款个人定制网站,保姆级教程,篇符较长,建议先保存收藏. 这篇文章,将从0到1,讲解如何利用AI编程开发并上线一款个人网站产品,包括 ...

  10. [VulnHub]DC-3靶场全过程

    DC-3 靶机部署 下载好DC-3,直接导入 可以生成一个mac地址,方便我们确认主机 信息收集 获取靶机ip(arp-scan/nmap) arp-scan -l nmap 192.168.190. ...