コガネブログ

平日更新を目標に Unity や C#、Visual Studio、ReSharper などのゲーム開発アレコレを書いていきます

【Unity】コルーチンと async / await を一緒に使用できる「Asyncoroutine」紹介

はじめに

「Asyncoroutine」を Unity プロジェクトに導入することで
コルーチンと async / await を一緒に使用できるようになります

Coroutine in async/await

using Asyncoroutine;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class Example : MonoBehaviour
{
    private async void Awake()
    {
        // 1秒待つ
        await new WaitForSeconds( 1f );

        // 1フレーム待つ
        await new WaitForNextFrame();

        // 1秒待つ
        await Task.Delay( 1000 );

        // WWW の通信完了を待つ
        var www = await new WWW( "https://api.ipify.org?format=json" );

        // 1秒待つ(Time.timeScale は無視)
        await new WaitForSecondsRealtime( 1f );

        // コルーチンの完了を待つ
        await UnityCoroutine();
    }

    private IEnumerator UnityCoroutine()
    {
        yield return new WaitForSeconds( 1f );
    }

    // OnDisable でもちゃんと動く
    private async void OnDisable()
    {
        await UnityCoroutine();
        var www = await new WWW( "http://google.com" );
    }
}

WaitForSeconds や WWW を async / await で使用できます
Awake や OnEnable、OnDisable でも async / await を使用できます

WaitForMainThread

using Asyncoroutine;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;

public class ExampleAwaitCoroutineSync : MonoBehaviour
{
    private async void Awake()
    {
        // ここは Unity のスレッド
        print( $"ThreadID : {Thread.CurrentThread.ManagedThreadId}" );

        await Task
            .Delay( 1000 )
            .ConfigureAwait( false )
        ;

        // ここは別のスレッド
        print( $"ThreadID : {Thread.CurrentThread.ManagedThreadId}" );

        await new WaitForMainThread();

        // ここは Unity のスレッド
        print( $"ThreadID : {Thread.CurrentThread.ManagedThreadId}" );
    }
}

別のスレッドを開始することができます
Unity のスレッドに戻ることもできます

Task in Coroutine

using Asyncoroutine;
using System.Collections;
using System.Threading.Tasks;
using UnityEngine;

public class ExampleUnityCoroutine : MonoBehaviour
{
    private IEnumerator Start()
    {
        // 1 秒待つ
        yield return new WaitForSeconds( 1f );

        // 1 秒待つ
        yield return Task.Delay( 1000 ).AsCoroutine();

        // タスクをコルーチンに変換する
        var taskYieldInstruction = Task.Run( () => { } ).AsCoroutine();
        yield return taskYieldInstruction;
    }
}

AsCoroutine 関数を使用することでタスクをコルーチンとして扱うことができます