コルーチン処理をキャンセル処理を含むUniTaskに置換する
Unity Learnにあるこのプロジェクト,キャラクターが死ぬと死ぬアニメーションの途中で GameOver画面が表示されてしまいます.
チュートリアルではTime.deltaTimeを使って間を入れていますが,
ここではコルーチン処理を使った場合と,UniTaskを使った場合にしてみます.
GameOverManager.cs 変更前
using UnityEngine; public class GameOverManager : MonoBehaviour { public PlayerHealth playerHealth; Animator anim; void Awake() { anim = GetComponent<Animator>(); } void Update() { if (playerHealth.currentHealth <= 0) { anim.SetTrigger("GameOver"); } } }
このチュートリアルのアセットはもうAsset Storeにない
このチュートリアルのアセット,実はもうAsset Storeにないので,ここではもう入手できません.
入手するには誰かのGitHubからcloneするしかない.
自分は以下からcloneしました.
コルーチン処理の場合
using UnityEngine; using System.Collections; // IEnumeratorが使えるようにするために必要 public class GameOverManager : MonoBehaviour { public PlayerHealth playerHealth; Animator anim; void Awake() { anim = GetComponent<Animator>(); } void Update() { if (playerHealth.currentHealth <= 0) { // コルーチン版 StartCoroutine(GameOver()); } } // コルーチン版ゲームオーバー処理 IEnumerator GameOver() { yield return new WaitForSeconds(2f); anim.SetTrigger("GameOver"); } }
2秒待ってから実行してる.
コルーチン処理は以下の記事を読むと良い.まとまっている.各所でよく取り上げられている. developers.wonderpla.net
(上記の記事,つい最近リンクが変わっているため,昔のリンクだと飛ばなくなっている
昔のリンク: http://developer.wonderpla.net/entry/blog/engineer/Unity_Co-routine/)
UniTask
UniTaskとは
これを読めば完結.
www.slideshare.net
実際に使ってみる.
とりあえずasync/awaitに置き換える
using UnityEngine; using UniRx.Async; // UniTaskのために必要 public class GameOverManager : MonoBehaviour { public PlayerHealth playerHealth; Animator anim; void Awake() { anim = GetComponent<Animator>(); } void Update() { if (playerHealth.currentHealth <= 0) { // UniTask版 GameOverAsync(); } } // UniTask版ゲームオーバー処理 async UniTask GameOverAsync() { await UniTask.Delay(2000); anim.SetTrigger("GameOver"); } }
実際にプレイしてみるとコルーチン処理の時と同じようになります.ただ,問題点があります.
無限に処理続けている
プレイをやめると以下のWARNが出ます.UniTaskには注意点があります.
UniTaskはシーンの切り替えや、オブジェクトの破棄では止まらない
裏でずっと続いてしまう可能性があるため,キャンセル処理を入れる必要があります.
それでは,キャンセル処理を含むUniTaskで書いてみます.
キャンセル処理を含むUniTask版
using UnityEngine; using UniRx.Async; // UniTaskのために必要 using UniRx.Async.Triggers; // GetCancellationTokenOnDestroy()のために必要 using System.Threading; // CancellationTokenのために必要 public class GameOverManager : MonoBehaviour { public PlayerHealth playerHealth; Animator anim; void Awake() { anim = GetComponent<Animator>(); } void Update() { if (playerHealth.currentHealth <= 0) { // キャンセル処理込みUniTask版 // 「this.GetCancellationTokenOnDestroy()」はオブジェクトの破棄で関数を止めるために必要 // Forget()をチェーンすることで警告を出さないようにする GameOverAsync(this.GetCancellationTokenOnDestroy()).Forget(); } } // キャンセル処理含むUniTask版ゲームオーバー処理 async UniTask GameOverAsync(CancellationToken cancellationToken) { await UniTask.Delay(2000, cancellationToken: cancellationToken); anim.SetTrigger("GameOver"); } }
いい感じにできました.
終わりに
UniRxだけでなく,Unity非同期処理,UniTaskも完全に理解したいなあ.難しいです. Unity Learn Premiumが今某ウイルスによって無料キャンペーンやってるので時間の合間にやっているのですが, なかなか良い題材がたくさんある,いい宝庫であることに今気づいた….早くやればよかったなあ.
この記事の題材になっているコースはもとから無料です.
参考資料
【Unite Tokyo 2018】さては非同期だなオメー!async/await完全に理解しよう
Unite2018でやってたセクション.参加した覚えがある.
www.slideshare.net
UniTask – Unityでasync/awaitを最高のパフォーマンスで実現するライブラリ
UniTask作成者による説明記事.