この講座は恋愛ホラーノベルゲームの作り方講座。今回は第5回目です。
前回はDoTweenを用いたアニメーション処理や画面遷移ユーティリティを作成しました。
前回の記事:
今回は作成した「UITransition」にUniTaskを使用した非同期・待機処理を実装して、前回作成したUITransitionクラスをより使いやすいプログラムに改造していきます。
前回&今回とシステム開発が多くなっていますが、これらをやっておくことで後々シーン数が多いノベルゲームの作成がとても楽になります。着実に習得していきましょう。
UniTaskを使用した待機処理の使い方をマスターしよう
UniTaskというのは、C#で使用できる非同期処理の機能「Task」をUnity向けに使いやすくしたものです。
まずは非同期処理というのを簡単に説明します。
非同期処理とは
非同期処理はコルーチンなどと同じようにちょっとわかりづらく、扱いが難しいです。
注意点も多いので、もしどうしてもわからないなと思ったら一旦流れだけ追ってコピペして使用することも考えましょう。
よくプログラミングではいかにコピペを使って短縮するかというのも重要だと言われたりします。後々使っていくうちにわかっていけば問題ありません。まず動かしてみて、数値を変えたりして何をしているか理解を深めていきましょう。
まず非同期の前に「同期処理」というのは、上から順番に処理を行う通常の処理のことを言います。
なので「非同期処理」というのは同期処理ではなく、ある処理の実行が終わらなくても次の処理にいく処理を言います。そしてその完了を「await」という命令で待ったりといったことができます。
直列にしか処理が行えないのが同期処理、並列で処理を行えるのが非同期処理とも言えますね。
この「待つ」処理を実現するためにUniTaskを使用すると思っても構いません。処理の順番が操作できるので便利な反面、プログラムが複雑になりがちなので今回は最低限の範囲で注意しながら使用していきます。
asyncやawaitという記載がある場合は非同期処理になっています。使用しながら少しづづ理解していきましょう。
なぜコルーチンでなくUniTaskがいいかというと、「記述がわかりやすくなる」、「返り値をとれる」、「MonoBehaviourでなくても使える」などの理由があります。
関連記事:Unity C#のIEnumerable・IEnumeratorとコルーチンの使い方・作り方
UniTaskにおいてこれがわかれば十分というものを先に書いておきます。細かいことは実際に使用するときにまた詳しく解説します。
1. Delayを使って遅延処理
一定時間(int型のms)待機して次の処理へ進む。コルーチンでは「yield return new WaitForSeconds( s )」。
2. WaitUntilを使って特定の条件まで待つ
3. WhenAllを使って複数のUniTaskを全て待機
UITransitionに待機処理を追加
では非同期処理を使用して「遷移が終了するのを待つ」処理を行えるようにUITransionクラスを修正していきます。
少し難しい修正になるのでまずは何をしているか流れの確認だけしてコピペしても大丈夫です。既にある関数の修正、新しい変数の追加、そして関数の形だけまずは作成します。
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
using System.Collections; using System.Collections.Generic; using UnityEngine; using DG.Tweening; using System.Threading; using UnityEngine.Events; using Cysharp.Threading.Tasks; [RequireComponent(typeof(CanvasGroup))] public class UITransition : MonoBehaviour { ・・・ //! インのキャンセルトークン. CancellationTokenSource inCancellation = null; //! アウトのキャンセルトークン. CancellationTokenSource outCancellation = null; async void Start() { await TransitionInWait(); Debug.Log( "遷移の終了" ); } // ---------------------------------------------------- // トランジションイン. // ---------------------------------------------------- public void TransitionIn( UnityAction onCompleted = null ) { ・・・(DOTweenの処理) inSequence .SetLink( gameObject ) .OnComplete( () => onCompleted?.Invoke() ); } // ---------------------------------------------------- // トランジションアウト. // ---------------------------------------------------- public void TransitionOut( UnityAction onCompleted = null ) { ・・・(DOTweenの処理) outSequence .SetLink( gameObject ) .OnComplete( () => onCompleted?.Invoke() ); } // ---------------------------------------------------- // トランジションイン終了待機. // ---------------------------------------------------- public async UniTask TransitionInWait() { } // ---------------------------------------------------- // トランジションアウト終了待機. // ---------------------------------------------------- public async UniTask TransitionOutWait() { } // ---------------------------------------------------- // 破棄された時のコールバック. // ---------------------------------------------------- void OnDestroy() { } } |
一番上「using」の部分に3つ追加があります。
「using System.Threading;」:こちらはC#のコードでスレッド関連の機能を使用するためのものです。今回は「CancellationTokenSource」を使用するために用いています。スレッドのキャンセルを制御するためのクラスです。
「using UnityEngine.Events;」:「UnityAction」を使用するために追加します。
「using Cysharp.Threading.Tasks;」:「UniTask」を使用するために追加します。
そして変数に「CancellationTokenSource」という型で「in」と「out」の二つを用意します。これはキャンセルトークンといって、TaskやUniTaskをキャンセルするために使用します。今回の修正ではまだこれらを用いた具体的な処理は書いていません。
次に「Start()」関数ですが、「async」という記述が追加されています。これは関数内で「await」を使用するために必要なもので非同期処理を行うために書いています。この二つはセットだと覚えてしまいましょう。
そして新しく追加した関数の「await TransitionInWait();」のように実行する関数に「await」を付けることでこの関数の終了を非同期で待ってから、それ以降の処理を行うようになります。今は適当にログを出して確かめています。
この「Start ()」関数の処理はテスト用ですので実装が終わったら削除します。
続いて通常の「TransitionIn()」、「TransitionOut()」の引数に「UnityAction onCompleted = null」と言うものを追加しました。
まずは「UnityAction」ですが、これは処理(関数など)を引数にして実行するための型と思っておけばOKです。これにより関数を実行する側から、指定したタイミングで処理を追加することができます。
そして引数に「= null」としてあると、引数の指定をしない場合にその初期値は「null」となります。
関連記事:UnityC# デリゲートとイベントとUnityActionの使い方
さらに関数内「inSequence」に前回解説した「.SetLink()」の後に追加する形で「.OnComplete()」という処理を追加しました。
ここでOnComplete()の中に入っている「 () => {} 」の部分は「ラムダ式」と呼ばれる記述方法で、「()」には通常の関数と同じように引数を、「{}」には処理を記載します。今は形で覚えてしまって構いません。
その関数内で「onCompleted?.Invoke()」引数は「onCompleted」を「Invoke()」、つまり実行しています。
「onCompleted」の後ろの「?」は、その値が「null」じゃなかったら、という意味になります。(if( OnCompleted != null ) と同じ意味)。
つまり全体ではDoTweenのシークエンス処理が完了し、さらにUnityActionが格納されているはずのonCompletedがnullじゃなかったらその処理を実行するという一行になります。
残りの関数は一旦形のみ作成します。トランジションの二つはどちらも「public async UniTask」になっておりここに待機処理を作成します。
「OnDestroy()」は非同期とは関係ないのですが、「Start()」関数などと同じようにUnityで用意されているもので、スクリプト内で書いておくと勝手に実行される系の関数です。
名前の通りこのゲームオブジェクトが破棄されたときに自動的に実行されます。
では追加した関数の中身を作成します。
次回に向けて
今回はUniTaskを用いたUI遷移処理を実装しました。また、クラスの継承を通して画面遷移ユーティリティの共通化のための足がかりを構築しました。
今回はまだBaseクラスを作成し継承しただけなので、次回から継承した側に実際の画面遷移処理を追加してゲームで使用できるようにしていきましょう。
次回の記事 :
コメント