当前位置:   article > 正文

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

unity unitask

一、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);            
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 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();
     }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

三、代码清单

代码【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();
        }
    }    
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 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

【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();
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 【3】测试结果
    测试环境Unity2017.4.37 Editor + Win10
    在这里插入图片描述
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/104480
推荐阅读
相关标签
  

闽ICP备14008679号