C#
Unity
C#7.0
UniTask

初心者向けコルーチンの代わり?UniTask(UniRx.async)を使い方


自己紹介

こんにちはゆずです。@Yuzu_Unity

自分はUnityエンジニア・3DCGデザイナーの学生です。(軸はエンジニア 4年ほど…)


はじめに

この記事はUnityのコルーチンを扱える人が

UniTask(UniRx.async)を扱えるようになればいいと思って書いています。

非同期処理以外については触れていません。

UniRxは全く関係ないです。

この記事ではUniRxについては記述しません。


こういう人向け?

複数フレーム待つ動作を頻繁に使いたい人?

セーブデータなどのIO関係を触る人

コルーチンに戻り値が欲しいと思っている人

C#7.0で色々使えるようになりたい人


環境構築編

C#7.0環境 IDEであればVisualStudio2017 Rider等

Unity2018.3以上

GitHubでUniTask(UniRx.async)

https://github.com/Cysharp/UniTask

もしくは AssetStoreでUniRxダウンロード(現在はGitHub版推奨 UniRxとUniTaskは分離されるみたいです。)

https://assetstore.unity.com/packages/tools/integration/unirx-reactive-extensions-for-unity-17276

※UniRxとは別物ですが同じパッケージに入っている

.NET 4.xモードにする(Player Settings→Other Settings)

image.png


UniTaskとは

C#7.0でasync/await Taskを扱えるようになったが,

Unityが公式でサポートしておらずこのままではコルーチンの代わりとして扱えないので

それを解消するライブラリです。

つまり逆に入れないと思ったように動かないと思ったほうがいい⁉

(Taskがメインスレッドで動いていないので、メインスレッドで動くTexture2D.EncodeToPNGなどは動作しませんでした。)


使い方

書き方

実行 関数名();

関数 async void 関数名() { }

実行 await 関数名();
関数 async UniTask 関数名() { }

実行 変数 = await 関数名();
関数 async UniTask<戻り値の型> 関数名() { }

の3つ

IEnumerator と async void が大体同じです。



  • コルーチン


void Start()
{
StartCoroutine(TestCoroutine());
}
IEnumerator TestCoroutine()
{
//WWWクラス定義
WWW www = new WWW("http://urx3.nu/QwZk");
//wwwダウンロード開始
yield return www;
Debug.Log("Complete");
}


  • UniTask

//using UniRx.Async;

void Start()
{
TestUniTask();
}

async void TestUniTask()
{
//WWWクラス定義
WWW www = new WWW("http://urx3.nu/QwZk");
//wwwダウンロード開始
await www;
Debug.Log("Complete");
}

ほとんど変わらないですね

IEnumeratorがasync

yield returnが await

という感じですね

これではメリットがあまりわからないので複数フレーム待機、戻り値ありにしてみましょう

//using UniRx.Async;

async void Test()
{
//TestUniTask終了まで待つ
int a = await TestUniTask();
Debug.Log("Complete");
}

async UniTask<int> TestUniTask()
{
//5フレーム待つ
await UniTask.DelayFrame(5);
return 3;
}

複数フレームはコルーチンだと1フレームのループ処理になり

無駄な処理が挟まれて結構重かったりしますね。


キャンセル処理

UniTaskの最大のデメリットです

コルーチンではStopCoroutine()もしくは

コンポーネントをOFFで止まることができました。

UniTaskはコンポーネントをOFFにしても止まりません!!

なのでゲームオブジェクトを消しても動きつづけます。

キャンセル処理に関してはここを参照してください

https://qiita.com/toRisouP/items/4445b6b9bf00e49eb147#%E3%82%AD%E3%83%A3%E3%83%B3%E3%82%BB%E3%83%AB%E5%87%A6%E7%90%86

キャンセル処理するならコルーチン現役ですね…


まとめ

停止が面倒なので

普通のゲーム制作のみであればコルーチンのほうがいいが

複数フレーム待つ動作を頻繁に使うのであればUniTask

セーブデータ、AssetBundleのダウンロード書き込み等

IO関係はUniTaskを使うほうがC#に用意されている非同期系が使えるので良い

要は併用しようという感じですかね!

また、ここには書いていませんがマルチスレッドプログラムもかけるのでそこに関してはゲームでも実用できるかと思います。

C#jobsystemの制約は少しめんどくさいですしね