1. アカウントを作成してログインする

プレイヤーのアカウントを作り、保存した情報でログインし直せるようにします。

まずはゲームにログインできるようにしましょう。ログインしたプレイヤーの ID を画面に表示し、Unity の再生を止めても、同じアカウントで戻ってこられるようにします。

初回はアカウントを作成して、プレイヤー ID とパスワードを保存します。2 回目からは保存した情報でログインします。ログイン後に受け取るアクセストークンには期限があるので、次に起動するときもログイン処理を通します。

1. プレイヤーを保存する場所を作る

GS2 の設定やデータを分けて置く場所を「ネームスペース」と呼びます。プレイヤーのアカウントを保存するために、GS2-Account のネームスペースを作りましょう。

「引き継ぎ設定」を追加する

Studio の Adventure プロジェクトを開きます。左側で機能を追加を押し、検索欄に 引き継ぎ と入力してください。メニューが見当たらない場合は、右上のシンプルを選びます。

引き継ぎ設定のカードで、追加を押します。このパッケージには、プレイヤーのアカウントを保存する Account の設定も入っています。

「機能を追加」で引き継ぎ設定を検索した画面。カードの「追加」を押す

カードに追加済みと表示されたら、Studio への読み込みは完了です。

引き継ぎ設定のカードに「追加済み」と表示された状態

サーバーに反映する

追加した設定を GS2 に送って、実際にアカウントを保存できるようにします。この作業を「デプロイ」と呼びます。

左側で反映を押し、サーバに反映するの枠にあるサーバとの差分を確認を押してください。

反映画面の「サーバに反映する」から「サーバとの差分を確認」を押す

GS2 ログインが表示されたら、準備で登録した開発者アカウントのメールアドレスとパスワードでログインします。

GS2 の開発者アカウントでログインする画面

ログインできたら、デプロイ先と変更内容を確認します。

  1. GS2プロジェクト選択で、学習用の adventure プロジェクトと 東京(ap-northeast-1) を選び、選択を押します。
  2. GS2への変更を確認で、引き継ぎ設定のパッケージ foundation-core-identity の差分を確認します。新しいプロジェクトでは、Account というネームスペースが作られます。スタック名は Studio が用意した名前を使います。
  3. 1パッケージをデプロイを押し、処理が完了するまで待ちます。
  4. 反映に戻り、サーバに反映するの枠が最新の内容を反映済みになっていることを確認します。

これで、プレイヤーを保存する Account ネームスペースができました。

コンソールから Account を作る

SDK コースでは、adventure-account というネームスペースをテンプレートから作ります。

  1. マネージメントコンソールで、学習用プロジェクトの東京リージョンを開きます。
  2. Deploy → スタックリスト → スタックを新規作成を選びます。
  3. 下のリンクからテンプレートをダウンロードします。スタック名を adventure-login にし、テンプレートデータでダウンロードした 01-account.yaml を選びます。
  4. 作成を押し、実行状態が作成完了になるまで待ちます。
GS2TemplateFormatVersion: "2019-05-01"
Description: Adventure tutorial - player accounts
Resources:
  AccountNamespace:
    Type: GS2::Account::Namespace
    Properties:
      Name: adventure-account
Outputs:
  AccountNamespaceName: !GetAttr AccountNamespace.Item.Name

このテンプレートをダウンロード

2. Unity にログイン処理を追加する

SDK と生成コードを Unity に入れる

追加した「引き継ぎ設定」を Unity から使うために、必要なファイルを Unity プロジェクトへ書き出します。この操作で、GS2 と通信する SDK、ログイン用のコンポーネントを含む GS2-Bind、選んだ機能を呼び出すための C# コードがそろいます。

Studio の Adventure プロジェクトと、準備のページで作った Unity プロジェクトを開いておきましょう。Unity は再生を止め、Adventure シーンを保存しておきます。

1. 書き出す先の Unity プロジェクトを選ぶ

左側で反映を押します。Unity プロジェクトを更新するの枠にある、Unityプロジェクトを選択して更新を押してください。

反映画面。中央の「Unity プロジェクトを更新する」の枠から、Unity プロジェクトを選べる

フォルダーを選ぶ画面が開きます。選ぶのは、Assets・Packages・ProjectSettings が入っているフォルダーです。Unity プロジェクトの名前が AdventureUnity なら、次の AdventureUnity を選びます。

AdventureUnity/           ← このフォルダーを選ぶ
├── Assets/
├── Packages/
└── ProjectSettings/

Assets フォルダーや、Studio の設計データを保存したフォルダーを選ぶと、Unity プロジェクトとして更新できません。

フォルダーを選ぶと、更新内容の確認画面が開きます。更新先が自分の Unity プロジェクトになっていることを確認して、更新を押します。画像の更新先は撮影用の例です。

Unity の更新内容を確認する画面。更新先と追加される SDK を確認し、右下の「更新」を押す

この操作で、Assets/GS2Studio/Generated に C# コードを書き出し、Unity のパッケージ設定に SDK と GS2-Bind を追加します。Generated の中は更新時に作り直されるので、自分で書くスクリプトはその外に置きます。

2. Studio で書き出しの完了を確認する

更新が終わったら、Unity プロジェクトを更新するの枠を見ます。

  • 最新の内容を反映済みと表示されている。
  • 枠の下部にあるUnity プロジェクトが、選んだフォルダーになっている。
  • 生成先に Assets/GS2Studio/Generated と表示されている。

書き出し完了後。「最新の内容を反映済み」と表示され、枠の下部に Unity プロジェクトと生成先が載っている

一度連携すると、ボタンは連携中のUnityプロジェクトを更新に変わります。次に書き出すときは、このボタンを使います。書き出し先を変えるときは、表示されたフォルダーの右側にある変更して更新から選び直せます。

3. Unity でファイルの読み込みを確認する

  1. Unity Editor に戻ります。必要なパッケージのダウンロードと、C# コードのコンパイルが始まるので、処理が終わるまで待ちます。
  2. Project ウィンドウで Assets → GS2Studio → Generated を開き、C# ファイルが入っていることを確認します。Project ウィンドウが見当たらない場合は、Window → General → Project で開けます。
  3. Window → Package Manager を開き、プロジェクトに導入済みのパッケージ一覧で GS2 を検索します。io.gs2.bind、io.gs2.csharp.sdk、io.gs2.unity.sdk の3パッケージが入っていることを確認します。パッケージ ID は、各パッケージを選んだ詳細欄で確認できます。
  4. Window → General → Console を開き、赤いコンパイルエラーが出ていないことを確認します。

パッケージのダウンロードに失敗している場合は、Package Manager に表示されたエラーとネットワーク接続を確認してください。C# のエラーがある場合は、Console の赤い項目を選ぶと詳細を読めます。

接続設定を作る

Unity の Project ウィンドウで右クリックし、Create → Game Server Services → Core → Environment を選びます。作成したアセットを AdventureEnvironment とし、Inspector を次のように設定します。

項目入れる値
Nameadventure
RegionApNortheast1
Client IdDefault の ApplicationClientId
Client SecretDefault の ApplicationClientSecret

画像では認証情報を空欄にしています。自分のプロジェクトでは、上の表の値を入力してください。

AdventureEnvironment の Inspector。Name は adventure、Region は Ap Northeast 1

シーンで GameObject → Create Empty を選び、名前を Gs2 にします。Inspector の Add Component から、次のコンポーネントを追加します。

コンポーネント設定
GS2/Core/Gs2ClientHolderEnvironments に AdventureEnvironment を1件追加。Active Environment Name は adventure
GS2/Core/Gs2GameSessionHolder追加した状態で使う
GS2/Account/AutoLoginAccount Namespace は Account。Persist Account をオン
GS2/Account/PlayerPrefs Account StoreKey Prefix を adventure.main にする
GS2 Studio/Runtime/Gs2HolderRuntimeContextProviderClient Holder と Session Holder に、上で追加したコンポーネントを割り当てる

Environment の Name 欄と、Client Holder の Active Environment Name を一致させてください。アセットのファイル名だけを変えても、この設定にはなりません。

Gs2 の Inspector。Client Holder の Environments に AdventureEnvironment を割り当てる

同じアカウントを使えるようにイベントをつなぐ

AutoLogin のイベント欄で + を押し、同じ Gs2 オブジェクトを割り当てます。関数の選択では、引数を受け取る Dynamic 側を選んでください。

AutoLogin のイベント接続する関数
On Account CreatedGs2PlayerPrefsAccountStore.Remember(Dynamic の string, string)
On Restore AccountGs2PlayerPrefsAccountStore.Restore(Dynamic の Gs2AutoLoginAction)

Persist Account をオンにするだけでなく、この二つの接続が必要です。これで、初回に発行されたアカウント情報が保存され、次回の再生時に読み込まれます。

プレイヤー ID を表示する

Unity のテキストと Player ID Label をつなぎ、ログインしたプレイヤーの ID を表示します。

1. 表示用のテキストを作る

  1. GameObject → UI (Canvas) → Text - TextMeshPro を選び、名前を PlayerIdText にします。Canvas がない場合は、一緒に作成されます。
  2. TMP Importer が開いたら、Import TMP Essentials を押します。
  3. 日本語を表示するため、Noto Sans JP のフォントファイル(別タブ)を開き、Download raw file でダウンロードします。Unity の Project ウィンドウで Assets/Fonts フォルダーを作り、NotoSansJP-Regular.otf をドラッグして入れます。
  4. 入れたフォントを選び、Assets → Create → TextMeshPro → Font Asset → SDF を選びます。作成された Font Asset の名前を AdventureFont にし、Inspector の Atlas Population Mode を Dynamic にします。
  5. Hierarchy で PlayerIdText を選び、TextMeshPro の Font Asset に AdventureFont を割り当てます。
  6. Rect Transform で、画面上部に表示されるように位置と横幅を調整します。長い ID も読めるよう、横幅を広めに取ります。
  7. TextMeshPro の Text Input は空にします。表示する文字は、ログイン後にコンポーネントから受け取ります。

PlayerIdText の TextMeshPro 設定。Font Asset に AdventureFont を割り当て、Text Input は空にする

2. Player ID Label をつなぐ

PlayerIdText を選んだまま、Inspector の Add Component → GS2 → Core → Player ID Label を選びます。

項目設定
Session HolderHierarchy の Gs2 をドラッグして割り当てる
Formatプレイヤー ID: {userId}

On Update の + を押し、PlayerIdText 自身を割り当てます。関数の一覧から TextMeshProUGUI → Dynamic string → text を選びます。入力欄に固定の文字を書く項目ではなく、受け取った文字列を表示する Dynamic string 側を使ってください。

Player ID Label の設定。Session Holder は Gs2、On Update は PlayerIdText の TextMeshProUGUI.text に接続する

これでログインに成功すると ID が表示されます。保存したアカウントでログインし直したときや、ログイン後にこのテキストを有効にしたときも、現在の ID に更新されます。

ログイン中とエラーのメッセージを表示する

ID の表示とは別に、ログインの状況が分かるテキストも用意しましょう。

  1. Canvas の下にもう一つ Text - TextMeshPro を作り、名前を LoginStatus にします。PlayerIdText の下に配置します。
  2. Font Asset に先ほど作った AdventureFont を割り当て、Text Input に ログイン中です と入力します。
  3. Gs2 の AutoLogin にある On Auto Login Complete の + を押し、LoginStatus を割り当てます。TextMeshProUGUI → text の固定文字列を指定できる項目を選び、文字列の入力欄を空にします。ログインできたら、メッセージの文字だけが消えます。
  4. Client Holder と AutoLogin の On Error に、それぞれ LoginStatus を割り当てます。TextMeshProUGUI → text の固定文字列を指定できる項目を選び、ログインできませんでした。設定と接続を確認してください と入力します。こちらは Dynamic 側ではありません。

AutoLogin のイベント設定。Remember と Restore でアカウントを保存・復元し、完了時は LoginStatus の文字を消す。Key Prefix は adventure.main

シーンを保存してから再生します。ログイン中のメッセージが消え、プレイヤー ID が表示されれば成功です。

ログイン用のスクリプトを付ける

SDK の非同期処理は UniTask で待ちます。await の次の行は通信が完了してから実行され、エラーは catch で受け取ります。

  1. Assets/AdventureLogin.cs を作り、下のコードを貼り付けます。
  2. シーンに空の GameObject を作り、名前を Adventure にします。
  3. AdventureLogin を追加し、Inspector の Client Id と Client Secret に Default のアウトプットを設定します。
  4. Account Namespace は adventure-account、Account Slot は main にします。
  5. 再生すると画面左上にログインボタンが出ます。押して、プレイヤー ID が表示されることを確認します。
using Cysharp.Threading.Tasks;
using Gs2.Core.Model;
using Gs2.Unity.Core;
using Gs2.Unity.Util;
using UnityEngine;

public sealed class AdventureLogin : MonoBehaviour
{
    [SerializeField] private string clientId = "YOUR_CLIENT_ID";
    [SerializeField] private string clientSecret = "YOUR_CLIENT_SECRET";
    [SerializeField] private string accountNamespace = "adventure-account";
    [SerializeField] private string accountSlot = "main";

    public Gs2Domain Gs2 { get; private set; }
    public GameSession Session { get; private set; }
    private bool busy;
    private string message = "ログインしてください";
    private string SaveKey => $"adventure.{clientId}.{accountNamespace}.{accountSlot}";

    private void OnGUI()
    {
        GUILayout.BeginArea(new Rect(20, 20, 650, 170), GUI.skin.box);
        GUILayout.Label(message);
        GUI.enabled = !busy && Session == null;
        GUILayout.Label("保存先(main / practice など)");
        accountSlot = GUILayout.TextField(accountSlot);
        if (GUILayout.Button("ログイン")) Login().Forget();
        GUI.enabled = true;
        GUILayout.EndArea();
    }

    private async UniTask Login()
    {
        busy = true;
        message = "ログイン中です";
        try
        {
            if (Gs2 == null)
            {
                Gs2 = await Gs2Client.CreateAsync(
                    new BasicGs2Credential(clientId, clientSecret), Region.ApNortheast1);
            }

            var userId = PlayerPrefs.GetString(SaveKey + ".userId", "");
            var password = PlayerPrefs.GetString(SaveKey + ".password", "");
            if (string.IsNullOrEmpty(userId) != string.IsNullOrEmpty(password))
            {
                message = "保存したアカウント情報がそろっていません。保存先を確認してください";
                return;
            }
            if (string.IsNullOrEmpty(userId))
            {
                var create = await Gs2.Account.Namespace(accountNamespace).CreateAsync();
                var model = await create.ModelAsync();
                userId = model.UserId;
                password = model.Password;
                PlayerPrefs.SetString(SaveKey + ".userId", userId);
                PlayerPrefs.SetString(SaveKey + ".password", password);
                PlayerPrefs.Save();
            }

            var login = await Gs2.LoginAsync(
                new Gs2AccountAuthenticator(new AccountSetting
                {
                    accountNamespaceName = accountNamespace,
                    keyId = "grn:gs2:{region}:{ownerId}:key:default:key:default"
                }), userId, password);
            Session = login;
            message = "ログインしました。プレイヤー ID: " + Session.AccessToken.UserId;
        }
        catch (System.Exception error) { message = "接続できませんでした: " + error.GetType().Name; }
        finally { busy = false; }
    }
}

AdventureLogin.cs をダウンロード

AccountSetting.keyId の {region} と {ownerId} は GS2 が解決する既定鍵の指定です。このコードではそのまま使います。鍵のネームスペース名と鍵名は、どちらも default です。

新しいアカウントの情報は、ログインの前に保存しています。ログイン時の通信に失敗しても、次に押したときに同じアカウントで試せます。保存済みの情報でログインできなかった場合も、勝手に別のアカウントを作りません。

この教材では、端末内の保存先に PlayerPrefs を使います。暗号化されない保存領域なので、公開するゲームでは保存方法を選び直してください。プレイヤーのパスワードや Client Secret を画面・ログ・公開リポジトリへ載せないようにします。

3. 同じアカウントでログインし直す

一度再生を止め、もう一度ログインしてみましょう。プレイヤー ID が前と同じなら、保存したアカウントでログインできています。

操作期待する結果
初回のログインプレイヤー ID が表示される
Unity の Play を止め、もう一度再生してログイン同じ ID が表示される
再生を止め、ネットワークを切断してから再生・ログインエラーメッセージが表示される
ネットワークを戻し、再生を止めてもう一度再生・ログイン保存したアカウントでログインできる

Studio では再生を始めると自動ログインします。SDK では画面のログインボタンを押します。再生を止めても保存データは残ります。

練習:二人目のプレイヤーを作る

Studio では再生を止めて PlayerPrefs Account Store の Key Prefix を adventure.practice に変え、再生します。SDK でも再生を止め、AdventureLogin の Inspector で Account Slot を practice に変えて再生し、ログインします。元と異なるプレイヤー ID になったでしょうか。

試し終わったら再生を止め、Studio の Key Prefix を adventure.main、SDK の Account Slot を main に戻して再生し、ログインします。最初のプレイヤー ID に戻ることを確認してください。

次へ:冒険を登録して一覧に表示する