スポンサーリンク
データ管理・セーブ

Unity Gaming Services入門|Cloud SaveとAuthenticationでクラウド連携を実装

データ管理・セーブ

「クラウドセーブを実装したいけど、サーバーの知識がなくて何から始めればいいかわからない」——そんなふうに感じたことはありませんか。

実はUnity Gaming Servicesを使えば、専門的なサーバー構築の知識がなくても、ログイン機能やクラウド保存を自分のゲームに組み込むことができます。

この記事では、UGSの初期設定から、Authenticationによる匿名サインイン、Cloud Saveを使ったプレイヤーデータの保存・取得・削除まで、実際のコード例を交えて順番に解説していきます。

Unity Gaming Servicesとは?導入前に知っておきたい基本

Unity Gaming Services(UGS)は、ログイン認証やクラウドへのデータ保存、ランキング機能などを、Unity公式が提供するサービスとしてまとめて使えるようにしたものです。自分でサーバーを用意したり、データベースの仕組みを一から学んだりしなくても、クラウド連携機能をゲームに組み込めるのが大きな特徴です。

「クラウドに保存」と聞くと、これまで使ってきたPlayerPrefsやローカルのJSON保存と何が違うのか気になる方も多いはず。両者の一番の違いは、データがどこに置かれるかという点にあります。

  • PlayerPrefs・ローカルJSON保存:データは端末内に保存される。機種変更やアプリの再インストールをすると、原則としてデータは引き継がれない
  • Cloud Save:データはUnityのサーバー上に保存される。同じアカウントであれば、別の端末からアクセスしてもデータを呼び出せる

つまり「複数端末でデータを共有したいか」「端末をまたいでプレイを続けてほしいか」が、どちらを選ぶかの分かれ道になります。ローカル保存だけで十分な設定値と、クラウドで守りたい進行データとを、そもそも分けて考えるのがポイントです。

なお、クラウド連携の仕組みを使わずにセーブ管理をシンプルに整理したい場合は、こちらの記事で全体像を比較しているので参考にしてみてください。

また「サーバー連携までは不要で、まずは手軽にセーブの仕組みを整えたい」という場合は、アセットを使う方法もあります。実装からセーブ・ロードまでの流れは、以下の記事で詳しく紹介しています。

ワンポイント

クラウド連携なしでシリアライズやセーブの仕組みを整えたいだけなら、Easy Save のようなアセットを使う選択肢もあります。UGSと比べて設定がシンプルな分、複数端末間のデータ共有はできない点は押さえておきましょう。

ここから先は、実際にUnity CloudプロジェクトをUGSに接続するところから、順番に手を動かしながら進めていきます。


事前準備|Unityアカウント作成とプロジェクトのクラウド連携

UGSを使い始めるには、まずUnityアカウントを用意したうえで、プロジェクトとUnity Cloudをつなげておく必要があります。ここでつまずくと後の作業がすべて止まってしまうので、最初にしっかり済ませておきましょう。

始め方は「新しくプロジェクトを作る場合」と「すでにあるプロジェクトを後から連携する場合」の2パターンに分かれます。自分の状況に合う方を選んで進めてください。

Unity Hubで新規プロジェクトを作成する場合

これからプロジェクトを新しく作るなら、Unity Hubの作成画面でそのままクラウドと接続してしまうのが一番スムーズです。次の手順で進めます。

  1. Unityアカウントを作成する(すでに持っている場合はこの手順は不要です)
  2. Unity Hubを開き、「New project」を選択する
  3. Unity Organization(組織)など、必須項目を入力する
  4. 「Connect to Unity Cloud」のチェックボックスが選択されていることを確認する
  5. そのままプロジェクトを作成する

この「Connect to Unity Cloud」にチェックが入っていれば、プロジェクト作成と同時にUnity Dashboard側にもプロジェクトが自動で作られます。後から手動でつなぎ直す手間がかからないので、新規作成の場合はここを見落とさないようにしてください。

既存プロジェクトを後からクラウドに連携する場合

すでに開発を進めているプロジェクトにUGSを追加したい場合は、Unity Dashboard側で先にプロジェクトを作り、それをUnityエディター側から紐づける流れになります。

  1. Unity Dashboardにサインインする
  2. プライマリナビゲーションメニューから「Projects」を選択する
  3. 画面右上の「New」を選択する
  4. プロジェクト名と、COPPA(児童オンラインプライバシー保護法)の該当有無を入力し、「Create」を選択する
  5. Unityエディターで対象プロジェクトを開き、メニューから「Edit」→「Project Settings」→「Services」を選択する
  6. 「Use an existing Unity project ID」を選択する
  7. ドロップダウンから自分の組織と、先ほど作成したプロジェクトを選ぶ
  8. 「Link project ID」をクリックしてリンクを完了させる

注意

「Link project ID」を実行する前に、選択した組織とプロジェクトが正しいか必ず確認してください。誤ったプロジェクトIDにリンクしてしまうと、後から設定を紐づけ直す作業が発生します。

ここまで完了すれば、プロジェクトとUnity Cloudの連携は完了です。次は実際にAuthenticationとCloud Saveのパッケージをプロジェクトに追加していきます。


Authentication・Cloud Saveパッケージのインストール手順

プロジェクトとクラウドの連携ができたら、次は実際に使う機能のパッケージをUnity側に追加していきます。今回はログイン機能を担う「Authentication」と、データ保存を担う「Cloud Save」の2つをインストールします。

どちらもPackage Manager経由で数クリックで導入できるので、難しい設定作業はありません。

  1. Unityエディターで「Window」→「Package Manager」を選択し、パッケージマネージャーを開く
  2. リストビューで「Unity Registry」を選択する
  3. 検索バーに「services」と入力するか、リストから該当パッケージを探す
  4. 「Authentication」を選択し、「Install」をクリックする
  5. 同様に「Cloud Save」を選択し、「Install」をクリックする

それぞれのパッケージ名は次の通りです。スクリプトを書くときの確認用として控えておいてください。

  • Authentication:com.unity.services.authentication
  • Cloud Save:com.unity.services.cloudsave

ワンポイント

両方のパッケージが内部で使用する「Services Core」(com.unity.services.core)は、AuthenticationやCloud Saveをインストールした時点で自動的に一緒に取得されます。個別にインストールする必要はないので、見当たらなくても心配いりません。

インストールが終わったら、Package Managerの一覧に2つのパッケージが表示されているか確認しておきましょう。表示されていれば準備は完了です。次は、これらのパッケージをスクリプトから使えるようにする初期化の設定に進みます。




名前空間のインポートとUGS初期化コードの書き方

パッケージのインストールが終わったら、次はスクリプト側の準備です。UGSの機能を呼び出すには、必要な名前空間をスクリプトの冒頭に書き、ゲーム起動時に初期化処理を実行しておく必要があります。

ここを飛ばしてAuthenticationやCloud Saveのメソッドを呼び出そうとすると、エラーになってしまうので、最初に必ず済ませておきましょう。

必要な名前空間をインポートする

スクリプトの一番上に、以下のusing文をまとめて記述します。今後Authentication・Cloud Saveの機能を使うたびに必要になるので、テンプレートとして控えておくと便利です。

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using Unity.Services.Core;
using Unity.Services.Authentication;
using Unity.Services.CloudSave;
using Unity.Services.CloudSave.Models;

ゲーム起動時にUGSを初期化する

名前空間をインポートしたら、次はUGS自体を初期化する処理を書きます。これはゲームが起動してできるだけ早い段階で実行する必要があるため、MonoBehaviourのAwake()に書くのが基本です。

async void Awake()
{
    try
    {
        await UnityServices.InitializeAsync();
    }
    catch (Exception e)
    {
        Debug.LogException(e);
    }
}

この処理では、初期化中に何らかの問題が発生した場合に備えて、try-catchで例外をキャッチしてログに出力するようにしています。エラーが起きてもアプリが強制終了せず、原因を確認できる状態にしておくための書き方です。

初期化が完了しているかどうかを途中で確認したい場合は、次のように書くことでランタイム中にチェックできます。

UnityServices.State == ServicesInitializationState.Initialized

ワンポイント

この初期化処理は、Authenticationのサインインより先に完了している必要があります。Awake()での実行順序が保証されない構成になっている場合は、初期化が終わってからサインイン処理を呼び出すよう、順番を意識して設計しておくと安心です。

初期化コードが用意できたら、いよいよAuthenticationを使ってプレイヤーをサインインさせる処理に進みます。




Authenticationで匿名サインインを実装する方法

初期化処理が済んだら、いよいよプレイヤーをサインインさせる処理を書いていきます。今回使うのは「匿名サインイン」という方法で、プレイヤーにメールアドレスやパスワードの入力を求めることなく、その場でプレイヤー用のアカウントを作成できる仕組みです。

ゲームを開いてすぐに遊び始めてほしい場合や、まずは手軽にログイン機能を試したい場合に向いている方法です。

サインイン前のガード節とコールバックを用意する

サインイン処理を呼び出す前に、UGSがすでに初期化済みかどうか、また既にサインイン済みではないかを確認しておく必要があります。これを怠ると、同じ処理が重複して呼ばれてしまうことがあるためです。

あわせて、サインインの成功・失敗やサインアウトのタイミングを検知できるよう、イベントのコールバックを登録しておきます。

AuthenticationService.Instance.SignedIn += SignedInCallback;
AuthenticationService.Instance.SignInFailed += SignedInFailedCallback;
AuthenticationService.Instance.SignedOut += SignedOutCallback;

SignInAnonymouslyAsyncでサインインを実行する

準備ができたら、以下のメソッドを呼び出すことで匿名サインインを実行できます。処理は非同期で行われるため、awaitを使って結果を待つ形になります。

await AuthenticationService.Instance.SignInAnonymouslyAsync();

すでに一度サインインしたことがある端末であれば、SDKにキャッシュされたセッショントークンをもとに、以前のプレイヤー情報が自動的に復元されます。毎回新しいアカウントが作られるわけではない、という点は覚えておくとよいでしょう。

通信状況や認証の問題でサインインが失敗するケースに備えて、次の2種類の例外は必ずキャッチするようにしてください。

  • AuthenticationException:認証に関するエラー
  • RequestFailedException:通信リクエストに関するエラー

いずれの例外も、エラーコード(ErrorCode)をログに出力しておくと、後から原因を追いやすくなります。

サインインが成功すると、AuthenticationService.Instance.IsSignedInがtrueになり、プレイヤーを識別するための一意のIDをAuthenticationService.Instance.PlayerIdから取得できるようになります。このIDは、後ほどCloud Saveでデータを扱う際にも紐づいてくる重要な値です。

サインアウト処理を実装する

サインアウトさせたい場合は、以下のメソッドを呼び出します。あわせて、最初に登録したコールバックの解除も忘れずに行っておきましょう。

AuthenticationService.Instance.SignOut();

注意

匿名サインインだけで運用している場合、機種変更やアプリの再インストールを行うと同じアカウントには二度とアクセスできなくなります。この点についての具体的な対策は、記事後半の注意点セクションであらためて説明します。

サインインが完了すれば、プレイヤーごとにデータを保存する準備が整ったことになります。次はいよいよ、Cloud Saveを使ってプレイヤーのデータを保存・取得する方法を見ていきましょう。




Cloud Saveでプレイヤーデータを保存・取得・削除する方法

サインインができるようになったら、いよいよ本題のCloud Saveです。ここでは、プレイヤーごとのデータをクラウド上に保存し、必要なときに取り出したり削除したりする方法を順番に見ていきます。

使い方自体はシンプルで、キーと値のペアを送ったり呼び出したりする感覚に近いので、ローカル保存の経験がある方であれば違和感なく進められるはずです。

プレイヤーデータを保存する

データを保存するときは、まず保存したい内容をDictionary<string, object>としてまとめ、それをSaveAsyncに渡す形で実行します。

var data = new Dictionary<string, object>{
    {"firstKeyName", "a text value"},
    {"secondKeyName", 123}
};
await CloudSaveService.Instance.Data.Player.SaveAsync(data);

他のプレイヤーからも読み取れる状態、いわゆる「公開データ」として保存したい場合は、保存時にSaveOptionsでアクセス権限を指定します。

await CloudSaveService.Instance.Data.Player.SaveAsync(data, new SaveOptions(new PublicWriteAccessClassOptions()));

ランキングのように他プレイヤーへ見せたいデータと、個人の進行状況のように非公開にしたいデータでは、保存方法を分けて考える必要があります。この違いを意識しておくと、後から権限まわりで混乱しにくくなります。

プレイヤーデータを取得する

保存したデータを読み込むときは、取得したいキーをHashSet<string>で指定し、LoadAsyncに渡します。

var playerData = await CloudSaveService.Instance.Data.Player.LoadAsync(new HashSet<string> { "firstKeyName", "secondKeyName" });
if (playerData.TryGetValue("firstKeyName", out var firstKey)) {
    string textVal = firstKey.Value.GetAs<string>();
}

戻り値はディクショナリ形式になっているため、TryGetValueで目的のキーを探し、GetAs<T>()で使いたい型に変換して取り出します。公開・保護されたクラスのデータを読み込む場合は、以下のようにLoadOptionsを指定します。

  • 公開データを読む場合:new LoadOptions(new PublicReadAccessClassOptions())
  • 保護済みデータを読む場合:new LoadOptions(new ProtectedReadAccessClassOptions())
  • 他プレイヤーの公開データをIDから読む場合:new LoadOptions(new PublicReadAccessClassOptions(playerId))

保存時にどの権限で書き込んだかによって、読み込み側で指定するオプションも変わってくる点は覚えておいてください。

プレイヤーデータの削除・キー一覧の取得

不要になったデータは、キーを指定してDeleteAsyncで削除できます。

await CloudSaveService.Instance.Data.Player.DeleteAsync("key");

プレイヤーに紐づいて保存されているキーの一覧をまとめて確認したい場合は、ListAllKeysAsyncを使います。

await CloudSaveService.Instance.Data.Player.ListAllKeysAsync();

こちらも、公開・保護クラスのキー一覧を取得したい場合はオプションを指定することで対応できます。

注意

保存処理を安易に上書きし続ける実装にしてしまうと、通信タイミングによってはデータが破損するリスクがあります。安全な保存の考え方については、以下の記事で詳しく解説しているので、あわせて確認しておくことをおすすめします。

また、ゲームをアップデートしていく中で保存するデータの構造が変わることもあります。将来的なバージョン違いを見据えたセーブ設計については、こちらの記事も参考にしてみてください。

データの保存・取得・削除の基本操作ができるようになったら、次は文章や数値だけでなく、ファイル単位でデータをやり取りする方法を見ていきましょう。




プレイヤーファイルの保存・読み込みを行う方法

Cloud Saveでは、文字列や数値といったキーと値のデータだけでなく、ファイルそのものをクラウドに保存することもできます。1ファイルあたり最大1GBまで対応しているので、セーブファイルをまるごと共有したい場合などに便利です。

ここでは、ローカルにあるファイルをクラウドへアップロードし、読み込み、削除するまでの流れを見ていきます。

ファイルを保存する

ファイルを保存するときは、まずローカルのファイルをバイト配列として読み込み、それをSaveAsyncでアップロードします。

byte[] file = System.IO.File.ReadAllBytes("fileName.txt");
await CloudSaveService.Instance.Files.Player.SaveAsync("fileName", file);

ファイル名をキーとして扱う形になるため、同じ名前で保存すると上書きされる点は覚えておいてください。

ファイルを読み込む

保存したファイルを読み込む方法は2種類あります。用途に応じて使い分けてください。

  • バイト配列として一度に読み込む場合:byte[] file = await CloudSaveService.Instance.Files.Player.LoadBytesAsync("fileName");
  • ストリームとして読み込む場合:Stream file = await CloudSaveService.Instance.Files.Player.LoadStreamAsync("fileName");

ファイルサイズが小さいうちはバイト配列での読み込みで問題ありませんが、サイズが大きくなりそうな場合はストリームでの読み込みを検討すると、メモリの使い方に無駄が出にくくなります。

ファイルを削除する

不要になったファイルは、以下のメソッドでキーを指定して削除できます。

await CloudSaveService.Instance.Files.Player.DeleteAsync("fileName");

複数のセーブデータをファイル単位で管理したい場合、どのファイルをどのスロットに割り当てるかという設計もあわせて考えておく必要があります。セーブスロットの実装例については、以下の記事でJSONやPlayerPrefsとの比較も交えて解説しているので参考にしてみてください。

ここまでで、サインインからデータの保存・取得・ファイル管理までの基本的な実装は一通り押さえられました。次は、実装を始める前に知っておくべき注意点について整理していきます。




実装前に知っておくべき注意点(匿名アカウント・料金体系)

ここまでの手順で、サインインからデータ保存までは実装できる状態になりました。ただし、実際に運用していくうえでは、匿名アカウントの扱いと料金体系について、事前に判断しておいたほうがいいポイントがあります。

匿名サインインのままでいいか、アカウントリンクを追加すべきか

匿名サインインは手軽に使える反面、Google・Apple・Facebook・Steamといった外部IDプロバイダーと紐づけていない状態だと、アカウントを一度失うと二度と復元できません。プレイヤーが機種変更をしたり、アプリを一度アンインストールして再インストールしたりすると、それだけで元のデータにはアクセスできなくなってしまいます。

このリスクをどこまで許容できるかは、ゲームの性質によって変わってきます。判断の目安として、次のような視点で考えてみてください。

  • 短時間で遊び切れるカジュアルゲームで、進行データの重要度が低い→匿名サインインのみでも大きな支障は出にくい
  • 長時間の育成要素や課金アイテムを含み、データ消失が離脱に直結する→匿名サインインに加えて外部アカウントとのリンクを推奨する導線を用意したほうがよい

実装の順序としては、まず匿名サインインでゲームをすぐに始められる状態を作り、その後のタイミングで外部アカウントとのリンクを促す、という二段構えが基本的な考え方になります。

注意

課金要素や長期的な進行データを扱うゲームで匿名サインインのみの運用を続けると、問い合わせ対応のコストが増える原因になりがちです。早い段階でアカウントリンクの導線を用意しておくことをおすすめします。

どのサービスが無料枠の対象か

UGSは開発中や公開直後の小規模な段階であれば、多くの機能を無料の範囲内で利用できます。ただし、サービスごとに無料枠の基準は異なるため、どこまでが無料なのかをあらかじめ把握しておくと安心です。

サービス無料枠の目安
Authentication無料枠の範囲内で利用可能
Remote Config無料枠の範囲内で利用可能
Cloud Save月間の保存容量・読み書き回数に上限あり。超過分は従量課金
Analytics月間一定数のユーザーまでは無料とされているが、定義の詳細は条件により変わる場合がある

特にCloud Saveは、プレイヤー数が増えるほど保存回数や読み書きの回数も比例して増えていく性質があるため、リリース後にアクセスが伸びてきたタイミングで一度利用状況を確認しておくと、想定外の課金に気づきやすくなります。

ワンポイント

料金体系や無料枠の基準は変更されることがあるため、最新の条件は必ずUnity公式サイトのダッシュボードや料金ページで確認するようにしてください。

匿名アカウントのリスクと料金体系、どちらも「知らずに運用を続けてしまう」ことが一番の落とし穴になりやすいポイントです。実装した機能を公開する前に、この2点だけは一度立ち止まって確認しておくとよいでしょう。


よくある質問

Q
Cloud SaveとPlayerPrefsは併用してもいいですか?
A
併用して問題ありません。音量設定やグラフィック設定のように端末ごとに保持したい値はPlayerPrefsに、複数端末で共有したい進行データやアイテム情報はCloud Saveに、というように役割を分けて使い分けると管理しやすくなります。すべてをどちらか一方にまとめる必要はありません。
Q
保存したCloud SaveのデータはUnity Dashboardから直接確認できますか?
A
Unity Dashboard上から、保存されているデータの内容を確認することができます。デバッグ中に「実際に保存されているか」「値が正しいか」を目視で確かめたいときに使うと、コード側だけで原因を探すよりも早く問題を切り分けられます。
Q
匿名サインインの後から、外部アカウント(Google・Appleなど)に切り替えることはできますか?
A
匿名アカウントを削除して新規に作り直すのではなく、既存の匿名アカウントに外部アカウントをリンクする形で対応するのが基本です。具体的な実装方法は本記事の範囲を超えるため、別記事で詳しく取り上げる予定です。

※当サイトはアフィリエイト広告を利用しています。リンクを経由して商品を購入された場合、当サイトに報酬が発生することがあります。

※本記事に記載しているAmazon商品情報(価格、在庫状況、割引、配送条件など)は、執筆時点のAmazon.co.jp上の情報に基づいています。
最新の価格・在庫・配送条件などの詳細は、Amazonの商品ページをご確認ください。

スポンサーリンク