原カバンは鞄のお店ではありません。

Unityを使ったゲーム制作のあれこれを綴っていきます。

【Unity】Unitaskのタイムアウト処理にはTimeoutControllerを使おう

秋がない

暑い日が続くと思っていたら急に冬の気温で衣替えが間に合っていないウッカリさんな皆さんこんにちは。気がつくと駅前にはクリスマスイルミネーションが飾られていたり秋をすっ飛ばして突然冬がやってきたような気持ちなんですが、皆さんはどうでしょうか?

 

CEDEC + KYUSHU

以前からお知らせしていますが今週末11/23(土)に福岡の九州産業大学で開催されるCEDEC + KYUSHU 2024のインディーゲームコーナーにリズムアクションゲーム「Under A Groove」を出展します。

CEDECはゲーム開発者向けカンファレンスイベントでゲーム業界関係者による登壇・講演が主なイベントとなっていますが、CEDEC + KYUSHUでは会場にインディーゲームの展示コーナーが設けられており、来場者の方が各公演の合間などに展示作品を遊べるようになっています。
今年は約20タイトルが出展予定で「Under A Groove」もその出展タイトルに名を連ねる事ができました。

cedec-kyushu.jp

展示内容的には先月東京ゲームダンジョン6で展示した内容とほぼ同じなんですが、その時からは多少のブラッシュアップが出来ていると思います。
まぁ、CEDEC + KYUSHUに来場される方で東京ゲームダンジョン6でも遊ばれた方は(おそらく)いないと思うので、ゲーム内容は以下のプレイ動画の方を参照してください。

youtu.be

 

UniTask中のタイムアウト

ここ最近のUnity界隈では処理待ちの実装にUnity標準のCoroutineではなくUniTaskを使うケースが増えてきて、中には完全にUniTaskへ移行した開発者の方も多いです。

www.karvan1230.com

御多分に漏れず私も移行した口でCoroutineを使用する場面は殆ど無くなったのですが、GameObjectに紐づくCoroutineに比べて、UniTaskではGameObjectが非アクティブになろうがDestoryされようがタスクが死なない為、UniTaskを使う際にはCancel処理とその発生条件をキチンと意識しないとバグの温床になるというデメリットがあります。

特に「処理の完了待ち or タイムアウト」といった条件による非同期処理のキャンセルを実装する場合にはWaitUntil(条件がTrueになるまで待つメソッド)等に指定する条件の指定に頭を悩ませていたのですが、よくよく調べてみると「タイムアウト」という条件にはTimeoutControllerを使うのが最適だと分かりました。

cysharp.github.io

 

使い方

TimeoutControllerを使用する手順は以下の通り

  1. TimeoutControllerを作る
  2. TimeoutController.Timeout()から一定時間後にキャンセルされるCancellationTokenを生成する
  3. await時に2.で生成したCancellationTokenを渡す
  4. 正常終了時はTimeoutController.Reset()を実行する
  5. 例外発生時は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処理を忘れない
◇プライバシーポリシー

●個人情報の利用目的

当ブログでは、メールでのお問い合わせ、メールマガジンへの登録などの際に、名前(ハンドルネーム)、メールアドレス等の個人情報をご登録いただく場合がございます。

これらの個人情報は質問に対する回答や必要な情報を電子メールなどをでご連絡する場合に利用させていただくものであり、個人情報をご提供いただく際の目的以外では利用いたしません。

●個人情報の第三者への開示

当サイトでは、個人情報は適切に管理し、以下に該当する場合を除いて第三者に開示することはありません。

・本人のご了解がある場合
・法令等への協力のため、開示が必要となる場合

個人情報の開示、訂正、追加、削除、利用停止
ご本人からの個人データの開示、訂正、追加、削除、利用停止のご希望の場合には、ご本人であることを確認させていただいた上、速やかに対応させていただきます。

アクセス解析ツールについて

当サイトでは、Googleによるアクセス解析ツール「Googleアナリティクス」を利用しています。

このGoogleアナリティクスはトラフィックデータの収集のためにCookieを使用しています。このトラフィックデータは匿名で収集されており、個人を特定するものではありません。
この機能はCookieを無効にすることで収集を拒否することが出来ますので、お使いのブラウザの設定をご確認ください。

●免責事項

当サイトからリンクやバナーなどによって他のサイトに移動された場合、移動先サイトで提供される情報、サービス等について一切の責任を負いません。

当サイトのコンテンツ・情報につきまして、可能な限り正確な情報を掲載するよう努めておりますが、誤情報が入り込んだり、情報が古くなっていることもございます。

当サイトに掲載された内容によって生じた損害等の一切の責任を負いかねますのでご了承ください。

●プライバシーポリシーの変更について

当サイトは、個人情報に関して適用される日本の法令を遵守するとともに、本ポリシーの内容を適宜見直しその改善に努めます。

修正された最新のプライバシーポリシーは常に本ページにて開示されます。