一、UniTask(Cysharp.Threading.Tasks)和Task(System.Threading.Tasks)的区别
- 1、System.Threading.Tasks中的Task是.Net原生的异步和多线程包。
- 2、UniTask(Cysharp.Threading.Tasks)是仿照.Net原生的Task,await,async开发的一个包,该包专门服务于Unity,所以取名UnityTask,简称UniTask。
- 3、既然有Task了,为啥还要搞一个UniTask
- (1)Task可以用在PC和Android上,但是在WebGL上则会报错(与多线程的支持有关),你可以退而求其次,使用协程实现异步等待。但是这样容易形成两套代码,增加工作量。
- (2)UniTask则是用一套代码打天下【一套写法,适用于PC,Android,WebGL等等】,UniTask用协程把await,async统一到多个运行平台。
背景:之前用Unity2020 + UniTask开发的项目,结果用户的需求是要集成到Unity2017.4.37的一个工程文件里面,所有只能返祖了。
二、为Task增加新的功能
- 1、UniTask有WaitUntil(),而Task没有,只能手动添加一个
/// <summary>
/// 方法:WaitUntil
/// </summary>
/// <param name="predicate">条件语句</param>
/// <param name="sleep">delay事件</param>
/// <returns>Task</returns>
public static async Task WaitUntil(Func<bool> predicate, int sleep = 50)
{
while (!predicate())
{
await Task.Delay(sleep);
}
}
- 2、UniTask有DelayFrame(),而Task没有,手动添加一个
/// <summary>
/// 方法:等待X帧
/// </summary>
/// <returns>Task</returns>
public static async Task DelayFrame(int count)
{
var current = Time.frameCount;
while (Time.frameCount - current > count)
{
await Task.Yield();
}
}
- 3、UniTask中为多种UI实现了异步点击的方法,在Task模式下,如何为一个Button打造一个异步点击方法——OnClickAsync
- (1)使用扩展方法来实现
- (2)给一个button的OnClick绑定一个方法,发生点击事件时,更改一个bool标记
- (3)用Task的await来循环等待用于标记Button点击的bool标记是否为true
- (4)取消button上OnClick中之前绑定的方法
- (5)返回
/// <summary>
/// 为Button定制一个扩展方法:点击事件的异步等待
/// </summary>
/// <param name="button">按钮Button</param>
/// <param name="delayMs">循环等待中delay的时间-毫秒</param>
/// <returns>Task</returns>
public static async Task OnClickAsync(this Button button,int delayMs = 50)
{
bool clicked = false;
UnityAction ClickAction = () =>
{
clicked = true;
//Debug.Log($"ClickAction() was called {Time.realtimeSinceStartup}");
};
//Debug.Log("添加侦听");
button.onClick.AddListener(ClickAction); //此处不能用兰姆达,不然传入的是临时定义的方法,而不是提前定义的。
while (!clicked)
{
await Task.Delay(delayMs); //等待时间【ms毫秒】
}
//Debug.Log("移除侦听");
button.onClick.RemoveListener(ClickAction);
ClickAction = null;
}
三、代码清单
代码【1】——扩展Task
using System;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
/// <summary>
/// Task扩展工具 【System.Threading.Tasks 】
/// not UniTask 【Cysharp.Threading.Tasks】
/// </summary>
public static class TaskUtils
{
/// <summary>
/// 方法:WaitUntil
/// </summary>
/// <param name="predicate">条件语句</param>
/// <param name="sleep">delay事件</param>
/// <returns>Task</returns>
public static async Task WaitUntil(Func<bool> predicate, int sleep = 50)
{
while (!predicate())
{
await Task.Delay(sleep);
}
}
/// <summary>
/// 方法:等待X帧
/// </summary>
/// <returns>Task</returns>
public static async Task WaitFrame(int count)
{
var current = Time.frameCount;
while (Time.frameCount - current > count)
{
await Task.Yield();
}
}
/// <summary>
/// 方法:等待X帧
/// </summary>
/// <returns>Task</returns>
public static async Task DelayFrame(int count)
{
var current = Time.frameCount;
while (Time.frameCount - current > count)
{
await Task.Yield();
}
}
}
【2】——测试Task
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System.Threading.Tasks;
using System;
/// <summary>
/// 按钮被点击的事件绑定
/// </summary>
public class ButtonClicked : MonoBehaviour {
public Button myButton;
// Use this for initialization
void Start () {
Func<Task> Flow = async() =>
{
while (true)
{
Debug.Log($"等待按钮被点击-{Time.realtimeSinceStartup}");
await myButton.OnClickAsync();
Debug.Log($"按钮点击完成-{Time.realtimeSinceStartup}");
}
};
Flow();
}
}
- 【3】测试结果
测试环境Unity2017.4.37 Editor + Win10