この記事はQiita Unity Advent Calendar 2022 カレンダー2 の9日目の記事です。
◆前日は chroske さんの 【Unity】ワープポータル転送演出の作り方【AdventCalendar2022】 - かつて代官山らへんで働いてたengineerのUnityブログ でした。
◆次の日は nkjzm - Qiita さんの「なんかかく」です。
ちょくちょくハマる Input System ですが、またも今年のデジゲー博の準備中にWebGLビルド時に操作できなくなる症状にぶつかりました。その原因と解決策です。
目次
問題が発生した状況
デジゲー博2022に出展したVoxelorer BirdのWebGL版の開発中に問題が発生しました。Unityエディター上では問題なく操作できていたのですが、WebGLでビルドしたものをiPadで動かすと最初は問題なく操作できていたのにステージ選択シーンに移動してからゲームに戻ると操作できなくなりました。
以下のバージョンで問題が起きることを確認しています。
- Unity2021.3.14f1
- Input System 1.4.4
原因
Voxelorer BirdはスマホではTouchscreen、PCではマウス入力を使います。ゲーム中は移動先や押すブロックなどの指定。
ステージ選択では洞窟のスクロール操作なので役割が違います。
操作できなくなるのはゲームシーンのみでCanvas上のUIは操作できます。問題はPlayer Inputのようです。Player Inputはゲームシーンとステージ選択シーンそれぞれにアタッチしてあり、各シーン用のアクションを設定しています。
テストプロジェクトを作ってあれこれ試したところ、シーンを非同期で先読みして切り替える時にTouchscreenとKeyboard&MouseのSchemeが切り替わることが分かりました。
シーンの切り替えにSceneManager.LoadSceneAsync()を使い、かつ、AsyncOperationのallowSceneActivationをfalseにして次のシーンを非同期に先読みすることで、古いシーンと非アクティブ状態の新しいシーンが混在することで問題が発生していました。
普通にシーンを切り替える場合は古いシーンのPlayer Inputが破棄された後に新しいシーンが読み込まれるので問題は起きません。Voxelorer Birdではシーン切り替えの待ち時間を減らすために画面を覆う演出の開始と同時に裏で次のシーンを非同期に読み込んでいます。古いシーンのPlayer Inputがデフォルトの入力デバイスを保有したままだと新しいシーンのPlayer Inputが同じ入力デバイスを選択できないらしく、他の入力デバイスを選んでしまうのが原因でした。
解決策
原因が分かれば対策は簡単です。シーン切り替えで入力が不要になり次第、Player Inputがアタッチされているゲームオブジェクト上で以下のような処理を実行して、有効なPlayer Inputを無効にすることで解決しました。
foreach (var pi in PlayerInput.all) { pi.enabled = false; }
といいつつ、この解決策にたどり着いたのはデジゲー博後、このブログのための調査をしている時でした。デジゲー博では実行環境を調査して手動でSchemeを割り当てるプログラムで回避していました。アドカレ万歳!
まとめ
Voxelorer Birdで採用していた特殊なシーン切り替え方法と、Player Inputに全てを委ねて手抜きしたことが招いた問題でした。分かってみれば解決策はシンプルで、シーンの切り替え前にPlayer Inputを無効にするだけでした。状態切り替え時の余計な入力による不具合を防げるのでこの解決策は筋が良さそうです。
Input Systemは、一人用の非リアルタイムゲームのような環境だとオーバースペックで使いにくい印象があります。一人用の場合はどの入力デバイスでも操作できた方が楽です。システム設計も密結合で手を加えにくく、もう一段階の進化を願ってます。
以上、Unity Advent Calendar 2022 カレンダー2 の9日目の記事でした!
◆前日は chroske さんの 【Unity】ワープポータル転送演出の作り方【AdventCalendar2022】 - かつて代官山らへんで働いてたengineerのUnityブログ でした。
◆次の日は nkjzm - Qiita さんの「なんかかく」です。
クリスマスまであと16日!