バーチャルキャスト開発中に遭遇した謎バグ集
はじめに
こんにちは。バーチャルキャスト開発部、クライアントチームの ichi です。
開発をするにあたって、バグとの闘いは避けては通れないものです。新機能の実装、既存機能のアップデートをするたびに何度も我々エンジニアの前に立ちはだかり、我々の精神を削りつつも次々と葬り去られていきます。
しかし、そんな激戦の中でも時にはきらりと光る何かを持ち、こちらを魅了してくるバグが誕生します。この記事では、そんな開発中に起きたバグをちょっとした解説を添えていくつか紹介しようと思います。
時間停止バグ
こちらは私が作業中に一度席を立ち、その後戻ってきたときに偶然発覚したバグです。
HMDを被りなおして作業再開しようとしたところ、画面に映る自分のアバターが何故かおかしな挙動をしていることに気づきました。
さすがにこのような挙動を見てしまったら、何が起こっているのか気にならずにはいられません。しばらくあれこれ調べた結果、どうも「HMDがスリープ状態から復帰するか、SteamVRのダッシュボードを開いて閉じるか」をトリガーとして、様々な機能が「時間が停止したかのような挙動」を取ることが分かりました。
いくつか例を挙げると、
- SpringBone の入っている物体(アバターの髪の毛、スカート等)が重力が働いていないかのような挙動になる
- コントローラーを用いたキャラクターの移動/回転ができなくなる
- リングメニューが開けなくなる
- 時間経過で変化する描画処理が全て停止する
- ステージ変更できなくなる
- ※リングメニューが開けないのでデバッグ用UIから実行
- アイテムが出現しなくなる
- 同上
- タイトルに戻れなくなる
- 同上
など。思っていた以上に様々な機能が影響を受けていました。
原因
本当にシーン内の時間が止まっていました。
バーチャルキャストで使用している SteamVR の Unity Plugin の中には SteamVR_Render
というスクリプトがあり、その中に
- VRアプリケーションからフォーカスが外れた時に現在の Unity の timeScale を保存してから 0 にセットする
- フォーカスが戻った時に保存した timeScale に戻す
という処理があります。
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 |
float timeScale = 1.0f; // フォーカスが外れた・戻った時にこの関数が呼ばれる // 外れたときは hasFocus = false, 戻った時は hasFocus = true private void OnInputFocus(bool hasFocus) { // ----- 略 ------ if (hasFocus) { if (SteamVR.settings.pauseGameWhenDashboardVisible) { Time.timeScale = timeScale; } // ----- 略 ----- } else { if (SteamVR.settings.pauseGameWhenDashboardVisible) { timeScale = Time.timeScale; Time.timeScale = 0.0f; } // ----- 略 ------ } } |
もちろん、こちらの処理自体に特に問題はありません。対で呼ばれる限り、正常に timeScale の保存・復帰が行われます。本当の問題は上記のスクリプトがシーン上に2つ存在していたことでした。
つまり、timeScale の保存・復帰処理がそれぞれ続けて二度ずつ行われていたため、
- 片方では現在の timescale が正しく保存されるが、もう片方では上書き後の timescale(つまり0)が保存される
- その後の復帰処理で片方は正常な timeScale を Unity の timeScale に代入するが、その直後にもう片方の復帰処理で Unity の timeScale に 0 が代入される
ということが起き、その結果フォーカスが戻った後も Unity の timeScale が 0 のままになり、シーン内の時間が停止したままになっていたというわけです。
解決
重複しているスクリプトを取り除くことによって解決されました。
余談
正直なところ「世界の時間を任意で止められる」という状況、ちょっと楽しかったです。
ゲッダンバグ
まずこちらをご覧ください。見覚えのある方が多いと思います。
こちらのバグは様々な新機能が実装されたVer.1.7.0aのアップデート直後に発覚し、
- アバターが一定よりも低い位置に来たとき
- またその状態で移動しようとしたとき
上記の場合に、かの有名なゲッダンバグのごとく体が荒ぶる現象が確認されました。
こちらが発見、修正する前にユーザーの皆様に捕捉され、しばらくの間ちょっとしたゲッダン祭りになったとかならなかったとか。
原因
Ver.1.7.0aで追加された歩行時のアニメーションを制御するときに使っている値が発散していたのが原因でした。
問題になっていたのは歩行アニメーションを制御する際に使用している「腰の高さ」を表すパラメータでした。
制御処理の中ではアバターの姿勢に応じてアニメーション時に目指すべき腰の高さの値を算出し、その値を別途歩行アニメーションを制御するために使っているライブラリに渡しています。
しかし調査の結果、
- 頭の位置が低くなるような姿勢をとった時に「腰の高さ」の値が0に近い極端に小さな値になる
- 歩行アニメーション制御のライブラリの内部で「腰の高さ」の値が計算の分母として使用されている
ことが分かりました。
当然、極端に小さい値を分母にした場合計算結果は発散します。その結果アニメーション制御処理の中に非常に大きな数値が入ることになり、それに引っ張られアバターがとんでもない動きをするようになっていました。
解決
「腰の高さ」の値が一定のよりも小さくならないように制限を付けることにより解決されました。
余談その1
Slack にカスタムレスポンスが実装されました。「ゲッダン」と入力すると計7種類の選りすぐりのゲッダンの中からランダムに一つ表示されます。
余談その2
カスタム絵文字も追加されました。やったね。
動けバグ
4月某日、突如 Slack で
「設定UIのLanguagesが動かせる」
との報告とともに以下の gif 画像が投下されました。
あまりにシンプルかつインパクトのあるバグだったので瞬く間に弊社エンジニアのハートを
がっちりと掴み、
「これは残していいバグ」「イースターエッグでも良いのでは・・・?」
とまで言わしめました。
原因
実にシンプルで、いつからか該当のUIのパーツにUIをドラッグ可能にするコンポーネントが刺さっていたようです。
解決
発覚後、数日のうちに 残念ながら そのコンポーネントが取り除かれ動かないように修正されました。
余談その1
こちらも無事(?)カスタムレスポンスが実装されました。「動け」と発言すると表示されます。
余談その2
おわりに
開発中に遭遇するバグがすべてこのくらい愉快なものだったらどれほど良かったでしょうか。
これからも開発メンバーによって粛々と、時には賑やかにバーチャルキャストのバグ修正は続いていくことでしょう。温かい目で見守っていただければ幸いです。
では、またどこかでお会いしましょう。