秋がない
暑い日が続くと思っていたら急に冬の気温で衣替えが間に合っていないウッカリさんな皆さんこんにちは。気がつくと駅前にはクリスマスイルミネーションが飾られていたり秋をすっ飛ばして突然冬がやってきたような気持ちなんですが、皆さんはどうでしょうか?
CEDEC + KYUSHU
以前からお知らせしていますが今週末11/23(土)に福岡の九州産業大学で開催されるCEDEC + KYUSHU 2024のインディーゲームコーナーにリズムアクションゲーム「Under A Groove」を出展します。
CEDECはゲーム開発者向けカンファレンスイベントでゲーム業界関係者による登壇・講演が主なイベントとなっていますが、CEDEC + KYUSHUでは会場にインディーゲームの展示コーナーが設けられており、来場者の方が各公演の合間などに展示作品を遊べるようになっています。
今年は約20タイトルが出展予定で「Under A Groove」もその出展タイトルに名を連ねる事ができました。
展示内容的には先月東京ゲームダンジョン6で展示した内容とほぼ同じなんですが、その時からは多少のブラッシュアップが出来ていると思います。
まぁ、CEDEC + KYUSHUに来場される方で東京ゲームダンジョン6でも遊ばれた方は(おそらく)いないと思うので、ゲーム内容は以下のプレイ動画の方を参照してください。
UniTask中のタイムアウト
ここ最近のUnity界隈では処理待ちの実装にUnity標準のCoroutineではなくUniTaskを使うケースが増えてきて、中には完全にUniTaskへ移行した開発者の方も多いです。
御多分に漏れず私も移行した口でCoroutineを使用する場面は殆ど無くなったのですが、GameObjectに紐づくCoroutineに比べて、UniTaskではGameObjectが非アクティブになろうがDestoryされようがタスクが死なない為、UniTaskを使う際にはCancel処理とその発生条件をキチンと意識しないとバグの温床になるというデメリットがあります。
特に「処理の完了待ち or タイムアウト」といった条件による非同期処理のキャンセルを実装する場合にはWaitUntil(条件がTrueになるまで待つメソッド)等に指定する条件の指定に頭を悩ませていたのですが、よくよく調べてみると「タイムアウト」という条件にはTimeoutControllerを使うのが最適だと分かりました。
使い方
TimeoutControllerを使用する手順は以下の通り
- TimeoutControllerを作る
- TimeoutController.Timeout()から一定時間後にキャンセルされるCancellationTokenを生成する
- await時に2.で生成したCancellationTokenを渡す
- 正常終了時はTimeoutController.Reset()を実行する
- 例外発生時はTimeoutController.IsTimeout()でタイムアウトかどうかを判定する
注意すべき点はTimeoutControllerによるタイムアウトは例外がThrowされるので、それをCatchした箇所でタイムアウト時の処理を実装する、という点と、TimeoutControllerを使用したら必ずResetを実施する、という点です。
例としてLitMotionによるTweenの完了待ちの箇所にTimeoutControllerによるCancellationTokenを渡してタイムアウトを発生させてみます。
TimeoutController timeOutCt = new TimeoutController(); // 指定秒後にタイムアウトする CancellationToken を作成 CancellationToken timeOutToken = timeOutCt.Timeout(TimeSpan.FromSeconds(TimeOutTime)); try { // startPosからendPosまで移動(ToUniTaskにCancellationTokenを渡す) await LMotion.Create(startPos, endPos, SprintTime) .Bind(value => { Obj.transform.position = value; }) .ToUniTask(timeOutToken); // Goalテキスト表示 } catch { // TimeOutテキスト表示 } finally { timeOutCt.Reset(); }
上のコード内の「SprintTime」がTweenの動作時間、「TimeoutTime」がタイムアウト時間です。
これでSprintTime<TimeoutTime(タイムアウト前にTweenの動作が完了)ケースだと
上の動画の様に正常終了時の動作(Goalの文字が表示)となります。
これをSprintTime>TimeoutTime(Tweenの動作完了前にタイムアウト発生)とすると
タイムアウト発生による例外時の動作(Timeoutの文字が表示)となります。
まとめ
- UniTaskでタイムアウトをしたいならTimeoutControllerを使おう
- 例外のCatchとReset処理を忘れない