Unityでアプリ起動時のスプラッシュスクリーン表示中に画面をタッチされると、 タイトル画面の表示が一瞬だけしかされずに、ステージ選択画面へ遷移してしまう問題
スプラッシュスクリーンって何?
スプラッシュスクリーン(スプラッシュ画面)とは、アプリを開いてから起動が完了するまでのつなぎとして表示される画像のことです。Apple Storeでアプリを公開する場合にはこのスプラッシュ画面はストア申請時に必須であり、使用するアプリの向きや、対応デバイスのサイズに適しているものを提供する必要があります。
Untiyで制作されたアプリにはデフォルトでは上図のようなUntiyのロゴが表記されたスプラッシュ画面が用意されています。Unity Personal Edition(無料版)ではこのスプラッシュ画面を変更する事はできませんが、Unity Professional Edition(有料版)では黒と白の2パターンから選ぶ事ができますし、非表示にしたり、任意のテクスチャを使用する事もできます。
前提条件
今回の問題を確認した環境は下記の通りになります。
- Unity5.4.1f1
- Unity Personal Edition (無料版)
- XperiaZ3
問題点
アプリの流れ
エディター上のテストではスプラッシュ画面は再生されないので気付けないのですが、実機テストをしてみるとスプラッシュ画面周りの挙動で問題が発生しました。今回問題に遭遇したアプリでは下図のような遷移の流れになっています。
アプリを開くとまずはスプラッシュ画面が表示されています。スプラッシュ画面が非表示になるとタイトル画面が見えるようになります。タイトル画面では画面全体を覆うuGUIのImageが貼られていて、画面をタッチするとEventTriggerのPointer Clickからステージ選択画面へ遷移するための関数が呼び出されます。
※画像はiOS/Androidで2016年10月リリース予定のアプリです。当ブログ主が初めて制作するゲームになります。よろしくおねがいします。
発生した問題
アプリ起動時のスプラッシュ画面表示中に画面をタッチされると、タイトル画面の表示が一瞬だけしかされずに、すぐにステージ選択画面へ遷移してしまいます。
問題の原因
この問題の原因はUntiyがスプラッシュ画面を非表示にする際の処理の流れにあります。
- Untiy有料版の場合
- 最初のSceneの読み込み開始と同時にスプラッシュ画面を表示
- Sceneの読み込みが完了したらスプラッシュ画面を非表示、同時に各スクリプトが動作を開始
- Unity無料版の場合
- 最初のSceneの読み込み開始と同時にスプラッシュ画面を表示
- Sceneの読み込みが完了したら各スクリプトが動作を開始
- 一定時間後(約10秒)にSceneの読み込みが完了していたらスプラッシュ画面を非表示にする
つまりこの問題の原因は、Untiy無料版ではSceneの読み込みが完了して各スクリプトが動作を開始しているのにもかかわらず、規定の時間経過するまではスプラッシュ画面が画面全体を隠し続けている事です。
スプラッシュ画面の表示非表示はスクリプトの動作に関与しないようになっているので、もしタイトル画面にボタンを用意していたら、それはスプラッシュ画面で隠されているだけで既にそこにはあるので押されてしまえば反応してしまいます。無料版の場合ではスプラッシュ画面は約10秒間という長い時間ずっと表示され続けるので画面を触ってしまうユーザーも多いと思います。また、この仕様は今回の問題以外にも様々な問題を引き起こすことが想像できます。アニメーションの再生開始タイミングがずれたり、音がずれたり、他にもたくさんあると思います。
解決策
Application.isShowingSplashScreen
Application.isShowingSplashScreenって何?
スプラッシュ画面が表示されているか確認します。アプリケーションが現時点でスプラッシュ画面を表示している場合は true を返します。
失敗例
初めにネットで調べて真似をしてみたのですが、Unityのバージョンによる違いのせいか、期待していた結果は得られませんでした。また、Unity5.3系では、Application.isShowingSplashScreenの値が変化しない不具合があるようなので注意して下さい。Unity5.4系では既に対応済みです。
成功例
上述した書き方では解決しませんでした。どうやら、スプラッシュ画面中で「画面にタッチした」瞬間にUpdate関数を通過するのではなくて、「画面にタッチした」という情報を保持したまま、スプラッシュ画面が閉じて、それから改めて「画面にタッチした」という情報を送っているように見えます。なので一度Update関数を何もさせずに通過させて「画面にタッチした」という情報を空振りさせようと考えて、下記のように書き直しました。処理の場所をEventTriggerからの呼び出しではなく、Update関数内に移動しています。そして、「スプラッシュ画面が閉じてから一度Update関数を何もせずに通過したか」のフラグを用意しました。
これで無事に解決しました。