Unity Game SimulationによるUnityアプリケーションの高速シミュレーション

#Unity Game Simulation

Unity Game Simulationは、GoogleのクラウドによってUnity製のアプリケーションの高速シミュレーションを可能にする機能です。
https://unity.com/ja/products/game-simulation

2019年のUniteで自動シミュレーション機能の概要とそれが開発状態であることが発表され、3月に行われたGoogle for Game Developer Summitにてこの機能が発表されました。

<img width="1017" alt="スクリーンショット 2020-04-26 22.08.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/c8333f30-ec22-983b-4b35-494421ec36d9.png">

<img width="1332" alt="スクリーンショット 2020-04-27 0.43.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/cb2e7f6f-dd9d-e9af-f3a8-33f05514768c.png">

<img width="1153" alt="スクリーンショット 2020-04-26 23.16.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/a5d0609b-8243-18ec-d510-373c37c2a1e0.png">


アプリケーションにSDKを組み込んでアップロード、そしてシミュレーションしたいパラメータをダッシュボード上で設定するとそれに従ってクラウド上で実行してくれるという機能です。
シミュレーションの結果も自分で定義して出力することができます。tsvファイルとして出力され、ダッシュボード上で確認することができます。

現在はベータ版となっていて、Unity側に試用することを申し込むとSDKなどが届き試せるようになります。
本記事では筆者が触ってみた際のやり方を紹介していきます。
<font color="Tomato">（*本記事のUnity Game Simulationのバージョンは0.3.0-preview.4となっています。今後の更新で機能や手順が変わる可能性がありますのでご注意ください）</font>

# 必要なもの

アプリケーション側が準備として必要なのは以下の要素です。

- Unity Servicesとの連携
- バージョン2018.3以降のUnity
- Linux向けビルドツール
- ゲーム終了後のApplication.Quitの呼び出し
- <b>自動的にアプリケーションが進行するシステムの実装

Unity Servicesとの連携についてはエディタ上で画面を開いて設定ができます。
公式のマニュアルが一番わかりやすいので、ここを見て設定してください。

https://docs.unity3d.com/ja/2018.4/Manual/SettingUpProjectServices.html

そして何より重要なのが最後の項目です。
この機能は自動シミュレーションを行う機能ではありますが、よしなにアプリケーションを操作してくれる機能ではありません。
なので、ゲームであればそのゲームループの開始と終了がユーザー操作なく完了してApplication.Quitを叩くところまで自動でやる必要があります。
ユーザー操作ありきのゲームを自動でプレイしてもらいたい！とかは厳しいので、最近のソーシャルゲームで多いようなオートモードの用意だったり、専用にAIを実装する必要があります。
専用のAIを用意する場合にはそのAIの性質によってシミュレーション結果が大きく偏ってしまうこともあるので、その点についてはかなりの注意が必要です。

# 導入手順

使ってみたいという方は現状ベータ版なので申し込みが必要です。
下記リンクの下の方から申し込みができます。
https://blogs.unity3d.com/jp/2020/03/24/optimize-your-game-balance-with-unity-game-simulation/

<img width="1064" alt="スクリーンショット 2020-04-26 22.18.35.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/9df5a044-bbf4-e4ce-d236-dce132d2d834.png">

自分の場合は１週間ほど経ってから返信が来ました。申し込み開始してから間もない時期にやったので、今だともう少し早いかもしれません。

返信には英語の手順書とSDKのリンクが入っています。手順を日本語化したものを本記事では書いていきます。

### SDKの導入
SDKは手順書からzipで落とせます。解凍すると二つのパッケージが入っています。
<img width="399" alt="スクリーンショット 2020-04-26 22.38.41.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/ae37674c-f876-a7f4-dd8a-8da4161d3071.png">
ローカルのpackageについてはPackage Managerのメニューから追加可能です。メニュー左上の「+」アイコンを押して、「Add Package from disk」を選択します。

<img width="360" alt="スクリーンショット 2020-04-26 22.54.33.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/002373e1-48d3-94e8-cb04-9c4a1c26cdae.png">

二つのpackage配下にあるpackage.jsonを選択して正常に読み込まれると画像にチラッと見えているようにUnity Game SimulatorとUnity Simulation Coreがpackageとしてリストに出てきます。これでSDKの導入は完了です。

### SDKを用いた実装

導入したSDKの機能を用いることで、自分がダッシュボード上で設定した値の流し込みや、結果となる値の出力を行うことができます。
主に使うのは*GameSimManager*というクラスです。

``` cs
GameSimManager.Instance.FetchConfig(response =>
{
    int intValue = response.GetInt("intValueKey");
    float floatValue = response.GetFloat("floatValueKey");
    string stringValue = response.GetString("stringValueKey");
    bool boolValue = response.GetBool("boolValueKey");
    long longValue = response.GetLong("longValueKey");
});
```
まず使うのが、上記のFetchConfigというメソッドです。ダッシュボード上で設定した値をstringのキーを元に取得することが可能です。
この値をよしなに使ってシステム側にシミュレーションに反映させます。

``` cs
// 出力する値の設定
GameSimManager.Instance.SetCounter("score", Score);
// 出力する値のリセット
GameSimManager.Instance.ResetCounter("score");
// 出力する値に対してインクリメントを行う
GameSimManager.Instance.IncrementCounter("score", 1);
```

シミュレーション結果を出力するために必要なのが上記の処理です。これらは出力して欲しいデータを定義するためのもので、たとえばゲーム内のスコアや時間だったり、結果を解析するためのログとして欲しいものを調整します。

### パラメータの設定

ダッシュボードからシミュレーションに流し込む値を設定するには、そもそもの値を定義する必要があります。定義はUnityのエディタ上で行うことが可能です。

<img width="465" alt="スクリーンショット 2020-04-27 0.00.28.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/a27da26f-6cfb-49e7-3dbb-1e89d1615f76.png">

上の画像のようにWindowメニューにGame Simulationというのが追加されているのでそれを開きます。

<img width="621" alt="スクリーンショット 2020-04-27 0.00.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/3b6fad1b-8ce1-8409-0cdc-d4e31afbf04e.png">

開くと上の画像のような画面が開きます（画面が開かない場合はUnity Servicesとの連携が正常にできているかを確認してください）。
Parameter Set Upが流し込むパラメータ定義の画面で、Build Uploadは後述するアプリケーションのアップロードを行う画面です。
パラメータの追加は下にあるAdd Parameterから可能で、stringのキーとTypeの設定、そしてデフォルトの値の設定が必要になります。手元のエディタ上で動かす際にはこのデフォルトの値が読み込まれます。
値を設定して右上のSaveを押すと通信が走り、値が保存されます。

### アプリケーションのアップロード

アプリケーションの実装が完了したら、Linux向けのビルドを行いアップロードをする必要があります。

<img width="625" alt="スクリーンショット 2020-04-27 0.17.21.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/76bcb5de-95e9-42cd-909c-ad78c000a1a8.png">

先ほどのシミュレーションに流し込む値の定義をした画面でBuild Uploadのタブボタンを押すと上の画像の画面が出現します。
ここでビルドするシーンと名前を設定してBuild and Uploadボタンを押すとビルドが走り、アップロードまで自動で行ってくれます。

<img width="390" alt="スクリーンショット 2020-04-27 0.21.19.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/6d0b9ad3-a860-ed27-0808-4734d97f974a.png">

アップロードまで完了すると上画像のようなログがでます。表示されているidというのがダッシュボード上でのビルドの識別子です。後述しますが、シミュレーションを回すビルドを選択する際に必要になります。

### ダッシュボードでの操作

ダッシュボードを操作するページは下記のリンクか、さっき説明したエディタのGame Simulationの画面の右上にあるCreate Simulationボタンから飛ぶことができます。

https://gamesimulation.unity3d.com/all-projects

<img width="625" alt="スクリーンショット 2020-04-27 0.25.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/f9877abe-cb1b-11ef-bbce-e82336237573.png">

開くときにUnity Idによるサインインが必要になるので、連携したUnity Servicesに紐づいているアカウントを選択してください。

<img width="1150" alt="スクリーンショット 2020-04-27 0.28.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/baaf131b-f8d7-62c0-1531-eab740fc5608.png">


開くとプロジェクトを選択する画面が出てきます。上の画像では空白になっていますが、左の部分に紐づいているUnityのプロジェクトが一覧として表示されます。
ここからUnity Simulationとしてビルトをアップロードしたプロジェクトを選択します。

<img width="1185" alt="スクリーンショット 2020-04-27 0.23.27.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/d4fe77d4-d83c-3d8e-5687-a3493eef6da7.png">

選択すると上の画像のようなダッシュボードが開きます。トップで表示されているのは作成したシミュレーションとその結果で、Download Resultsから結果ファイルのダウンロードが可能です。
シミュレーションを新しく作成するには右上のCreate Simulationを押します。

<img width="1332" alt="スクリーンショット 2020-04-27 0.43.16.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/cb2e7f6f-dd9d-e9af-f3a8-33f05514768c.png">

Create Simulationを押すとシミュレーションの名前、対象のビルド、流し込むパラメータ、シミュレーション回数を設定する画面が開きます。
対象のビルドではビルドの名前ではなく、Game Simulation側で管理しているIdでの指定になります。これについては先述しているビルドのアップロード時のログを参照してください。
パラメータについては、カンマ区切りで複数の値が可能です。

<img width="628" alt="スクリーンショット 2020-04-27 0.48.10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/007a19fe-7a4d-964d-048e-eb8628fc5b42.png">

例えば上の画像であれば3つのキーに3つずつ値が設定してあります。シミュレーション側ではこれらの組み合わせを網羅的に回してくれるので、
(attack, defence, life) = (3,0,1)
(attack, defence, life) = (4,0,1)
(attack, defence, life) = (5,0,1)
(attack, defence, life) = (3,1,1)
...
といったようなシミュレーションのパターン化が可能になります。これが結構便利なので、活用することをおすすめします。
<img width="953" alt="スクリーンショット 2020-04-27 0.54.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/ef29e430-87f5-be9f-224c-06ad38f03781.png">

パラメータを設定し終えたらRunを押すとシミュレーションが開始されます。シミュレーション中はトップ画面でStatusがRunningという状態で表示されているので完了するまで待ちましょう。
完了すると、先ほど説明したように、結果データのダウンロードが可能になります。

<img width="774" alt="スクリーンショット 2020-04-27 0.57.24.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/30e5636b-7f88-f66c-9481-ffcf818818a7.png">
<img width="900" alt="スクリーンショット 2020-04-27 0.57.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141004/0f26fc66-06e5-0792-da91-ff96e14aaaae.png">

結果データは上画面のように、パラメータとその結果が格納されています。ここにあるパラメータひとつひとつはSDKを用いた実装で説明した*GameSimManager*によって設定されたものです。
シミュレーションを回した中での平均値や最小値最大値など、解析に役立つ形で記録されています。


# 料金

現状、40000分/月の利用が無料で提供されています。これは個々のシミュレーション時間とその回数の掛け算による合算の時間です。なので、回すシミュレーションを高速化する工夫だったり回数の調整が必要になります。

月に40000分を超えるシミュレーションを回す場合には料金を払う必要があるそうです。ただ、必要な場合にはメールで問い合わせてその料金体系を返答として返すとのことだったので、まだ有償で使う予定のない筆者は具体的な値段までは把握していません。
もし、企業などでガッツリ使いたいという場合には公式に問い合わせてみましょう。

# 機能の使い所
クラウド上で高速でシミュレーションをぶんわしてくれるのは、公式でも説明している通りレベルデザインなどに役立つかなとは思います。
自動シミュレーション系のゲームのレベルデザインにおいて、パラメータの調整とその試験運転のイテレーションというのはとてもコストのかかるものです。
Unity Game SimulationであればGoogleのリソースを活用して並列に多くのシミュレーションを高速で回してくれます。
個人開発でめちゃくちゃ使うかというと微妙な線ではありますが、大規模化しているソーシャルゲームのステージ運用とか新キャラ運用を効率化する上で、Unity Game Simulationは活躍の場がありそうだなと個人的には考えています。

ただ、現状では出力形式やパラメータ形式の制約、そもそもの機能の使い勝手などもまだ開発段階かなとも感じますので、今後の開発次第ではより多くの機能をまかなえる可能性もあるかなと感じています。
人的リソースを大幅に削減するツールとして期待していきたいですね。