UniTaskDemo:在 Unity 中的各种高级用法与最佳实践的示例类。

0 阅读3分钟

概述(Overview)

UniTaskDemo 是一个专注于展示 UniTask(Cysharp.Threading.Tasks)在 Unity 中的各种高级用法与最佳实践的示例类。

主要演示内容包括:

  • 异步方法通过委托跨脚本传递与调用
  • 按钮点击的异步流(AsyncEnumerable)处理
  • 使用异步 LINQ 操作点击事件(Take、Where、ForEachAsync 等)
  • 不同方式实现“等待指定次数点击”的逻辑
  • 异步 Update 循环(EveryUpdate)
  • 取消令牌(CancellationToken)的使用场景
  • UniTask 事件订阅(Subscribe)与延迟组合
  • UniTaskManager(自定义任务管理器)的基本使用示例

适用于需要精细控制异步流程、事件流处理、取消支持的场景(如引导流程、加载、交互序列、多阶段操作等)。


方法一览(API Index)

方法名访问级别异步返回类型主要功能典型用途
DoSomethingAsyncprivateUniTask连续等待三次按钮点击并打印日志基础多阶段点击等待示例
UpdateDemoprivateUniTask异步方式实现每帧 Update替代传统 Update 的异步写法
EveryTwoClickprivateUniTask每两次点击触发一次逻辑演示异步流 + Where 筛选
ThreeClick1privateUniTask使用 AsyncClickEventHandler 等待3次点击传统顺序等待方式
ThreeClick2privateUniTask使用 Take(3) + LastAsync 等待3次点击简洁等待固定次数点击
ThreeClick3privateUniTask使用 Take(3) + ForEachAsync 监听3次点击每次点击都执行操作 + 最后总结
DelayDemoprivateUniTask订阅点击事件,点击后延时1秒执行演示 Subscribe + 延迟组合
TaskDemopublic staticFunc<CancellationToken, UniTask>暴露给外部的异步任务委托跨脚本/模块调用异步流程
ActionDemopublic staticAction暴露给外部的同步委托(未使用)

静态字段 / 公开接口

TaskDemo

/// <summary>
/// 可被外部脚本调用的异步任务委托
/// 支持 CancellationToken 取消
/// </summary>
public static Func<CancellationToken, UniTask> TaskDemo;

初始化位置:通常在 Awake 中赋值

典型用法(其他脚本):

UniTaskDemo.TaskDemo?.Invoke(cts.Token).Forget();

核心方法详情

DoSomethingAsync

/// <summary>
/// 连续等待用户点击三次按钮,每次点击打印对应日志
/// </summary>
/// <param name="ct">用于取消的令牌</param>
private async UniTask DoSomethingAsync(CancellationToken ct)
{
    await okButton.OnClickAsync2D(ct);
    Debug.Log("第一次点击");

    await okButton.OnClickAsync2D(ct);
    Debug.Log("第二次点击");

    await okButton.OnClickAsync2D(ct);
    Debug.Log("第三次点击");
}

最基础的顺序等待多次点击示例。


UpdateDemo

/// <summary>
/// 使用 UniTask.EveryUpdate() 实现异步每帧循环
/// 可通过 CancellationToken 优雅停止
/// </summary>
private async UniTask UpdateDemo(CancellationToken ctk)
{
    await foreach (var _ in UniTaskAsyncEnumerable.EveryUpdate().WithCancellation(ctk))
    {
        Debug.Log("Update() " + Time.frameCount);
    }
}

替代传统 Update() 的现代写法,支持取消。


EveryTwoClick

/// <summary>
/// 每两次点击才执行一次逻辑(使用 Where 筛选偶数索引)
/// </summary>
private async UniTask EveryTwoClick(CancellationToken ctk)
{
    await okButton.OnClickAsAsyncEnumerable()
        .Where((x, i) => i % 2 == 0)
        .ForEachAsync(_ => { Debug.Log("click"); }, cancellationToken: ctk);
}

展示如何对点击事件流进行过滤。


ThreeClick1(使用事件处理器)

/// <summary>
/// 使用 GetAsyncClickEventHandler 顺序等待三次点击
/// </summary>
private async UniTask ThreeClick1(CancellationToken ctk)
{
    using var handler = okButton.GetAsyncClickEventHandler(ctk);
    await handler.OnClickAsync();
    await handler.OnClickAsync();
    await handler.OnClickAsync();
    Debug.Log("点击三次");
}

最直观的顺序写法,推荐在逻辑清晰时使用。


ThreeClick2(使用 Take + LastAsync)

/// <summary>
/// 等待正好三次点击后继续(不关心中间过程)
/// </summary>
private async UniTask ThreeClick2(CancellationToken ctk)
{
    await okButton.OnClickAsAsyncEnumerable()
        .Take(3)
        .LastAsync(cancellationToken: ctk);
    
    Debug.Log("点击三次");
}

最简洁的“等待三次点击”写法。


ThreeClick3(每次点击都响应)

/// <summary>
/// 等待三次点击,每点击一次都打印,结束后总结
/// </summary>
private async UniTask ThreeClick3(CancellationToken ctk)
{
    await okButton.OnClickAsAsyncEnumerable()
        .Take(3)
        .ForEachAsync(_ => { Debug.Log("每次点击"); }, cancellationToken: ctk);
    
    Debug.Log("三次点击完成");
}

适合需要在每次点击时都有反馈的场景。


DelayDemo(订阅 + 延迟)

/// <summary>
/// 每次点击后延迟1秒再执行操作
/// </summary>
private async UniTask DelayDemo(CancellationToken ctk)
{
    okButton.OnClickAsAsyncEnumerable().Subscribe(async x =>
    {
        await UniTask.Delay(TimeSpan.FromSeconds(1), cancellationToken: ctk);
        Debug.Log("延时结束");
    });
}

展示事件订阅与异步延迟的组合使用。


UniTaskManager 使用示例(代码中注释部分)

// 创建带 ID 的任务
var (id, cts) = UniTaskManager.CreateIdTask();
DoSomethingAsync(cts.Token).Forget();

// 取消指定任务
UniTaskManager.CancelIdTask(id);

// 创建带字符串标识的任务
var (key, cts2) = UniTaskManager.CreateStrTask("LoadScene");
DoSomethingAsync(cts2.Token).Forget();

// 取消全部任务
UniTaskManager.CancelAllTasks();