うどんてっくメモ

技術的なメモをまったりと

【Unity】サーバーレスで定数管理!サンプルで学ぶRemote Config【Unity Gaming Service】

はじめに

本記事は、Unity Advent Calendar 2023 20日目の記事になります。 検証環境は以下になります。バージョンが違う場合には動作しない場合がありますので、ご留意ください。

  • Unity2022.3.11f1
  • Unity Gaming Services Use Cases 1.10.0

Unity Gaming Service

Unity Gaming Service(以下、UGS)はゲームでよく必要となる機能を使いやすい形でUnityが提供しているサービスです。自前でサーバーを設けたりせず、さまざまな機能を実現することが可能です。

unity.com

2023年の頭にもUGSについては紹介記事を出しています。こちらでは「Cloud Code」や「Cloud Save」といったサービスについて触れていますので、興味のある方はそちらもご覧ください。

myudon.hatenablog.com

Remote Config

Remote Configは必要な定数をゲーム中のコードではなく、UGS上で管理することのできるサービスです。 ゲームをビルドして更新せずとも、ゲーム中の定数を調整してリリースすることが可能です。

unity.com

stringのkeyと保存する値をペアにして、任意の定数をリアルタイムで設定することができます。

バトル中のダメージ係数だったり、何かしらのアイテムの消費数だったり、さまざまな定数が存在しますが、変更するたびにビルドするのは面倒です。そこで、定数をゲームのバイナリとは別のサーバーなどで保管するのはひとつの手段です。

一定の規模感のある開発であれば自前で運用することも検討できますが、小規模な開発ではこれを運用をするのはハードルが高いです。 そこで、サーバーレスでこういった機能を使えるRemote Configが活躍します。

A/B Test for Level Difficulty

今回はA/B Test for Level Difficultyを見ていきます。 これはゲーム開発におけるプレイ継続率や課金率といった指標に対する有効なパラメータを探るための仕組みのサンプルです。どのパラメータが有効かを探るために、ゲーム上でパラメータを色々と試せる仕組みをUGSを用いて実現しています。

github.com

サンプルの実行やダッシュボードの確認を行うまでには、クローンして起動、そして各種サービスのセットアップ処理が存在します。こちらの説明は署略しますので、上記リンクの公式手順に従ってください。

プロジェクトを起動し、A/B Test for Level Difficultyのシーンを実行します。 プレイヤーの経験値ゲージとボタンが表示され、ボタンを押すと経験値の上昇とレベルアップが確認できます。

UGSのサンプルということで、以下の機能がUGSによって実現されています。

UGS 機能
Analytics プレイヤーの行動解析
Authentication プレイヤー認証
Cloud Code プレイヤーの経験値上昇
Cloud Save プレイヤーの経験値やレベルなどの情報の保存
Economy ゲーム内通貨の管理
Game Overrides プレイヤーの経験値テーブルの反映
Remote Config プレイヤーの経験値処理に関する定数管理

今回注目するのがRemote Configです。 このサンプルでは以下の定数を定義しています。前述したセットアップのタイミングでUGSのダッシュボードから設定します。

Key Type 内容
AB_TEST_GROUP string プレイヤーのグループ
AB_TEST_ID string テストのID
AB_TEST_LEVEL_UP_XP_NEEDED int レベルアップに必要な経験値
AB_TEST_XP_INCREASE int ボタン押したときの経験値獲得量
CURRENCIES json 通貨ごとのアイコンのパス指定

ちなみにダッシュボードにサクッとUnity上から行きたい時は、Servicesのところから「Go to Dashboard」から飛ぶのが簡単です。

Remote Configの設定

Remote Configの定数は前述の通りブラウザのダッシュボードから設定可能ですが、Unityのエディタ上でもAPIを介して専用のWindowで設定できるようになっています。

Unity上で設定を変更して反映を行うには「Push」を、逆にダッシュボード上での変更を取り込みたい時には「Pull」のボタンを押します。Unity上で変更した際には「Push」を忘れると変更が反映されないので注意してください。

型はintやstringから選択することが可能です。ちょっと複雑なパラメータを定義するときなどはjson形式で設定することも可能です。

各種UGSのセットアップが完了していれば、AB_TEST_LEVEL_UP_XP_NEEDEDとAB_TEST_XP_INCREASEを好きな数字に変えて試してみてください。 ボタンを押した時の経験値量やレベルアップの閾値が変わることが確認できるかと思います。

スクリプト上からRemote Configへの参照

定数を設定した後は、スクリプト上から参照する必要があります。サンプルがどのようにRemote Configの定数を取り扱っているかみてみます。 RemoteConfigManagerというクラスで、RemoteConfigServiceを経由してkeyをもとにC#上のDictionaryとして管理しています。RemoteConfigServiceから直感的にGetHogeHogeというメソッドで呼び出すだけでシンプルです。

また、通貨ごとのアイコンのパスが4種類あるのをCURRENCIESというjsonにまとめて管理しています。json形式の設定を活用することで、特定のデータ型に対応した定数を定義することも可能になっています(直感的な調整はやりづらくなるので、使う場面の注意は必要そうです)。

void GetConfigValues()
{
    levelUpXPNeeded = RemoteConfigService.Instance.appConfig.GetInt("AB_TEST_LEVEL_UP_XP_NEEDED");
    abGroupName = RemoteConfigService.Instance.appConfig.GetString("AB_TEST_GROUP");
    abTestID = RemoteConfigService.Instance.appConfig.GetString("AB_TEST_ID");
    var json = RemoteConfigService.Instance.appConfig.GetJson("CURRENCIES");
    currencyDataDictionary = CreateCurrencyDictionary(json);
}

Dictionary<string, CurrencySpec> CreateCurrencyDictionary(string json)
{
    var dictionary = new Dictionary<string, CurrencySpec>();

    var currencyDataHolder = JsonUtility.FromJson<CurrencyDataHolder>(json);

    foreach (var currencyData in currencyDataHolder.currencyData)
    {
        dictionary[currencyData.currencyId] = currencyData.currencySpec;
    }

    return dictionary;
}

また、このサンプルのレベルアップの実処理については、Unity上のC#ではなく、Cloud Code上で実行されています。 Cloud Code自体の実装はjavascriptで、プロジェクト配下のABTestLevelDifficulty_GainXPAndLevelIfReady.jsに実装されています。その中でもRemote Configへの参照が確認できます。

async function getRemoteConfigData(remoteConfig, projectId, environmentId) {
    const getRemoteConfigSettingsResponse = await remoteConfig.assignSettingsGet(
        projectId,
        environmentId,
        'settings',
        ["AB_TEST_XP_INCREASE", "AB_TEST_LEVEL_UP_XP_NEEDED"]
    );

    if (getRemoteConfigSettingsResponse.data.configs &&
        getRemoteConfigSettingsResponse.data.configs.settings &&
        getRemoteConfigSettingsResponse.data.configs.settings.AB_TEST_XP_INCREASE &&
        getRemoteConfigSettingsResponse.data.configs.settings.AB_TEST_LEVEL_UP_XP_NEEDED) {

        return {
            xpIncreaseAmount: getRemoteConfigSettingsResponse.data.configs.settings.AB_TEST_XP_INCREASE,
            xpNeededForNextLevel: getRemoteConfigSettingsResponse.data.configs.settings.AB_TEST_LEVEL_UP_XP_NEEDED
        };
    }

    throw new CloudCodeCustomError("Failed to get AB_TEST_XP_INCREASE or AB_TEST_LEVEL_UP_XP_NEEDED data from Remote Config.");
}

このCloud CodeとRemote Configの連携からもわかるように、UGS同士の連携が容易なのも便利な点です。

Game Overrideによる調整

このサンプルでは、Remote Configの定数群に対してテンプレートを用意して一括で反映する手段も説明しています。 それがGame Overrideです。

docs.unity.com

サンプルのREADMEでは、AB_TEST_GROUP、AB_TEST_ID、AB_TEST_LEVEL_UP_XP_NEEDEDをパターン分けして反映可能にしています。 セットアップの手順については公式のガイドを参考にしてください。 ダッシュボード上から、Remote Configの定数のパターンの定義と時間を設定することが可能です。

これによって、特定の定数の値をスケジュールに沿って反映することができます。機能を時限式で提供したり、イベントの運用をしたりすることが可能です。

サンプルではA/Bテストということで、パラメータのパターンによるユーザーの反応をテストする機能として活用されています。 ゲームの指標を測るためのオプションもいろいろと揃っているので、ストアでリリースしているゲームのパラメータを指標に沿って調整したい方はぜひ触ってみてください。

まとめ

サンプルから、Remote Configの使い方や他のUGSとの連携した使い方を学ぶことができました。ゲーム内の定数管理を柔軟にしたいけどどうしようかなと悩んでいる方は一考の余地はあるのではないでしょうか。

本記事はサンプルの全容は説明しておらず、つまんで紹介しています。詳細が気になる方は、ぜひともサンプルを手元で実行してみることをおすすめします。