Unity中的异步编程【5】——在Unity中使用 C#原生的异步(Task,await,async) - System.Threading.Tasks

一、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
    在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/dzj2021/article/details/128659483