OculusGo用の個人制作ゲームをストアリリース　～ストア審査はパフォーマンス確保との闘い～

#Oculusストアに申請してみよう
UnityでVRアプリを作るお勉強のため、OculusGo用のちょっとしたパズルゲームのようなものを作ってみました。
![mikanchan-web.png](https://qiita-image-store.s3.amazonaws.com/0/275693/3402523b-6c06-ed77-c878-92315fb8097e.png)
最初はただUnityプログラミングの勉強になればいいと思ったので、軽く作っておしまいにする予定でしたが、
折角だからいろんな人に遊んでもらいたいのと、
私のようなUnity始めたばかりの周回遅れおじさんには、この世界に転職するためのアピールポイントをしっかり作る必要があるので、
ちゃんとストアリリースの実績を作っていこうと思ったわけです。

いざストア申請をやってみると、それをクリアする作業だけでも非常に勉強になりました。
審査での指摘内容と解決の過程をお見せしたいと思います。

#アセットガイドラインを確認しよう
|審査概要|結果|要約|
|:--|:--|:--|
|Hero art must include the branding of the app centered in the image.|Logo/Branding isn't centered horizontally and vertically.|ヒーローアートのロゴが中央に配置されていません。|
|Trailer must not be longer than 2 minutes.|Trailer is 2 minutes and 12 seconds long.|動画が規定の2分より長いです。|
こちらは単純にアセットの規定違反に引っかかってしまいました。
アセット編集ページの上部にもリンクがあるアセットガイドラインをよく見ましょうというお話です。
私は何故かこれが目に入っていませんでした。
ヒーローアートってなんぞ？？　と首を傾げながら適当にそれっぽい画像をセットしましたが、ちゃんと解説と規定がありました。
動画も、登録ページに全ての規定が書かれているわけではありません。

#戻るボタンの機能は融通がきかない
|審査概要|結果|要約|
|:--|:--|:--|
|When the user presses the back button, the app must either go back one level in your UI or display a menu with an option to quit the app.|Game restarts when user presses the back button. The app should either go back one level within the UI or display a menu with an option to quit the app.|戻るボタンを押すとゲームリセットされます。戻るボタンを押したときは、１つ前に戻るかアプリ終了メニューを出さなければなりません。|
OculusGoコントローラーの戻るボタンにも自由な機能を持たせたくなるんですよね。
この制約のことは知っていましたが、リセットも「ゲームが戻る」という解釈にならないかな？？　と思って通してみましたが、ダメでした。
戻るボタンで終了メニューを出す場合は次のようなコードになります。

```
    if (Input.GetKeyDown(KeyCode.Escape))
    {
        OVRManager.PlatformUIConfirmQuit();
    }
```

メニューボタンでも同じような動作になるので、ちょっと勿体ない気もするのですが。
ちなみに、リセット機能は「トリガー＋クリック」で動作するようにしました。

#コントローラーの動作は左右両方の手で確認しよう
|審査概要|結果|要約|
|:--|:--|:--|
|The app must detect if the 3DOF controller is set to left-handed or right-handed, and it must function equally well when used with either configuration.|Controller graphic is no longer displayed when user sets controller to "Left Hand".|コントローラーを「左手」に設定すると、コントローラー画像が表示されません。|
左手！
そういえば確認していませんでした。不具合は確認が漏れたところに現れるものです。
どうして表示されないのか……
![image.png](https://qiita-image-store.s3.amazonaws.com/0/275693/6cda6dbe-0214-c36e-f943-e428feb5cd57.png)
あっ
![control_s.png](https://qiita-image-store.s3.amazonaws.com/0/275693/c88b7812-70b7-072b-6ce8-d2e1f0f2cd9b.png)
Tracked Remote Prefabのデフォルト値が右手なんですね。
左手のアンカーには左手の値を設定しなければなりません。
なまじ右手はデフォルト値で動いてしまうので、気付き難いところかもしれません。注意が必要です。

#ファイルの読み書きには権限要求が必要？
|審査概要|結果|要約|
|:--|:--|:--|
|The app must request the minimum number of permissions required to function.|Your app is asking for excessive user permissions or using user permissions inappropriately. - Access Photos, Media, Files on your device. Please remove all unnecessary permissions. If your app requires any of the permissions listed above please explain in detail why your app needs the permission in order to function.|不要にも関わらず「デバイス上の写真、メディア、ファイル」へのアクセス要求をしています。削除するか、もし必要であれば詳しく説明してください。|

アクセス要求を行っていたのは、もちろん不正にファイルを読み書きしようとしていたためではありません。
ただ、少しだけゲームの情報をファイルに記録して、そのファイルを読み込みたいと思ったのですが、
私がOculusGoでファイルの読み書きを行う方法を調べる過程で、次のような（英語の）文章があったためです。

> ファイルパスは"Application.persistentDataPath"が適切。
> ファイル読み書きを許可する場合は、マニュフェストに
> uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
> uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
> があることを確認してください。

これに従って設定していたのですが、本当に必要かどうかは検証していなかったので、確認することにしました。
もし、権限を要求しないで読み書きに成功すれば、必要がないためこの宣言を削除。
読み書きに失敗すれば、必要な理由を説明することになりますが……

成功しました。
必要なかったです＾＾

というわけで、宣言を削除しました。
ところで、もし必要だったとき、Oculusストアに説明すればよかったのか、それともアプリの説明文に加える必要があったのか、どっちなんでしょうね。
　⇒（追記）やはりユーザーから見てわかりにくいものであれば、アプリの説明文に加えるべきのようです。（コメントありがとうございます）

#VRアプリにとってパフォーマンス確保は最重要課題
ここまでは前置き。
簡単に問題点と解決方法がわかりましたが、残りの一つが難解で、かつ重要なものでした。

|審査概要|結果|要約|
|:--|:--|:--|
|The app displays graphics without judder.|Judder occurs when the user moves their controller side to side during gameplay.|コントローラーを横に動かしたときにジャダー（カクつき）が発生します。|

これは最初、意味がわかりませんでした。
カクついてる？？　コントローラーを左右に振ったとき？？

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Oculus「コントローラーを左右に振るとカクつくから直してね～＾＾」<br><br>え、これのこと？？　マジで？？　厳しいね……？ <a href="https://t.co/P9ZUQOGTmI">pic.twitter.com/P9ZUQOGTmI</a></p>&mdash; ほけ (@hoke946) <a href="https://twitter.com/hoke946/status/1029378964685385729?ref_src=twsrc%5Etfw">2018年8月14日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

私がそのとき見た限りでは、コントローラーの動きは正常で、極端にガクッとなるようなことはなく、問題ないように見えました。
Oculusストアに質問してみることにしました。

私「（たどたどしい英語で）この問題が認識できなくて困っています。この動画のような動きをもっと滑らかに改善すればいいのですか？　詳しく教えてください。」
Oculusストア「（普通の日本語で）レビューチームによりますと、ゲームプレイ中にユーザーがコントローラーを横に動かした場合にジャダーが発生するようです。」

審査結果を繰り返されただけでした……。
しかも日本語が通じたようで、ちょっと恥ずかしい……。

しかし、後日じっくりと確認してみると、確かに少しモタついているというか、全体的に重い感じがしました。
コントローラーに限ったことではありませんが。
そこでtwitterにリプライを頂きました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">この動画を拝見したんですが、多分言われてるのはコントローラを振りながら視界が動いたときに画面隅に黒い陰が映っちゃってるのが原因じゃないかなーと。確かこれはレビューリジェクト要因だったと思います。<a href="https://t.co/3IrmmCAPjG">https://t.co/3IrmmCAPjG</a></p>&mdash; nagoya0@10時間は寝たい (@nagoya0) <a href="https://twitter.com/nagoya0/status/1030074153221554176?ref_src=twsrc%5Etfw">2018年8月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

そして、井口氏のツイートを紹介されました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Oculus Goで開発してる方：首を振った時に視野の端に黒い縁が一瞬見える場合、現在のフレームレートが規定fps(60か72)に足りていません。身内で共有する場合などは平気ですが、Oculusストアに申請する場合は原則常に規定fpsを維持できている必要があるため、パフォーマンスチューニングをお忘れなく。</p>&mdash; Kenji Iguchi (@needle) <a href="https://twitter.com/needle/status/1000756393731764224?ref_src=twsrc%5Etfw">2018年5月27日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

つまり、私のアプリはパフォーマンスへの配慮が全く足りていませんでした。
VRアプリにとってパフォーマンス確保はデリケートで、不足は酔いに繋がります。
本来、原則として気を付けるべきということですね。

そして、神々からの助言。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">デバッグ用に現在のfpsを画面内に出す機能を用意しておくと良いです</p>&mdash; GOROman (@GOROman) <a href="https://twitter.com/GOROman/status/1030076434625097728?ref_src=twsrc%5Etfw">2018年8月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">開発中は視界内に常時フレームレートカウンターを表示しとくのをお勧めしますー</p>&mdash; Kenji Iguchi (@needle) <a href="https://twitter.com/needle/status/1030077645499682816?ref_src=twsrc%5Etfw">2018年8月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

常にFPSが安定して出せているかを確認できるようにしておくべしということです。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">FPSとか見たい場合は、OVR Metrics Toolが結構楽ですよ～（別途、ADBで呼び出す必要がありますが）<a href="https://t.co/AtxMZsiUi2">https://t.co/AtxMZsiUi2</a></p>&mdash; 🥦青木そらす🍤@持たざる者 (@open_sorasu) <a href="https://twitter.com/open_sorasu/status/1030078631815434240?ref_src=twsrc%5Etfw">2018年8月16日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

FPSを計測できるOVR Metrics Toolというものがあるようです。

ただ、ちょっと導入までにひと苦労必要そうだったので（ごめんなさい）、
今回はこちらのスクリプトを使用しました。

[【Unity】FPS を画面に表示するスクリプト](http://baba-s.hatenablog.com/entry/2017/12/20/000200#)

出力先は3Dテキストにします。
そして、自分のアプリを計測してみると、30fps前後をウロウロとしていました。

さて、どうすれば解消できるのか。

まずは何の処理に時間がかかってパフォーマンスを下げているかを

Window > Analysis > Profiler

で確認できるそうです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/275693/eaa15e7a-3ffa-e1f1-8e4b-da7da2d322aa.png)
Unityでそのままデバッグ実行するのは実機の環境とは違うし、細かい見方はよくわかっていませんが、
とにかくスクリプトの処理などはあまり問題ではなく、レンダリングに負荷がかかっていることがわかりました。
![mikan_old.png](https://qiita-image-store.s3.amazonaws.com/0/275693/8011faac-5882-56e7-d83d-336340fec7a5.png)
何のテクスチャもないただのCubeとはいえ、視界に100個余りのオブジェクトが展開されるのはキツいみたいですね。
イ○バ物置のようにはいきません。
視界に入るオブジェクトが減ると60fpsで安定するようになります。

解決へのアプローチとして、まずは影の処理を見直したりなどしてオブジェクトを軽くする方法を模索しましたが、私には効果的な方法がわかりませんでした。
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">参考までにどうぞ<a href="https://t.co/KiMYNVp6yC">https://t.co/KiMYNVp6yC</a></p>&mdash; GOROman (@GOROman) <a href="https://twitter.com/GOROman/status/1030986007347224576?ref_src=twsrc%5Etfw">2018年8月19日</a></blockquote>

紹介されたリンクには、VRアプリを最適化する方法が色々と書かれていました。
結局、ここに書かれている内容を参考にしても今回のパフォーマンスは改善はしなかったのですが、
次に何か作るときは、この資料を基礎にしたいと思いました。

オブジェクトを軽くする方法がうまくいかなかったので、
次はキャラクターの周囲以外のオブジェクトを表示しないようにして、表示オブジェクトを限定する方法を採ることにしました。

こちらは効果バツグンで、安定したパフォーマンスが出せるようになりました。
見た目が少し寂しい感じにはなりましたが、
サクサク動くようになったので、全表示されていたときより満足感が増したような気がします。

表示しなくてもいいもの、影響の少ないものは省いていくことが、特に今のモバイルVRアプリには必要なんですね。

これをもって、無事、審査を通すことができました！！

#最後に
ストアリリースは一度経験してみるべきですね。
ここまで勉強になるとは思いませんでした。
同じようにアプリ作成を勉強しようとしている方も、ストアリリースを目指してみることをお勧めします。

ただし、なんでもかんでも申請すればいいものではなくて、
まず自信を持ってリリースできるものを準備することと、
フリー素材の利用規約など、権利関係をクリアしておくことなどは、心掛けてくださいね。

そして、私も若干怠ってしまったところはありますが、
本来は先に各種ガイドラインには目を通して、クリアできていそうか確認すべきでしょう。

[アプリ公開概要ガイド](https://developer.oculus.com/distribute/)

とはいえ、自分の中だけで100パーセント一発OKを目指さなくても大丈夫。
そこそこ大丈夫だな？　と思ったら、思い切って申請すべし！　ですね。
あとはレビューをしながら解決していきましょう。

###「みかんちゃんパネル」をよろしく！
さて、今回リリースされた「みかんちゃんパネル」はOculusGoがあれば無料で気軽にプレイできます。
Oculusストアで「mikan」と検索すると出てきます。
是非、遊んでみてくださいね。

twitterハッシュタグ：[#みかんちゃんパネル](https://twitter.com/hashtag/%E3%81%BF%E3%81%8B%E3%82%93%E3%81%A1%E3%82%83%E3%82%93%E3%83%91%E3%83%8D%E3%83%AB?src=hash)