ルーム

ルームマッチメイキングを GS2 SDK for Unity から利用する手順を解説します。

ルームマッチメイキング とは

親となるユーザがルーム(ギャザリング)を作成します。

参加者となるユーザは、ルームの一覧を取得し、任意のルームを選択してルームに参加することでマッチメイキングを実現します。

この方式の弱点は、非常にプレイヤー数が多くなったときにルーム一覧取得からルームに参加するまでの間にルームが埋まってしまう。という点です。

そのため、特別な理由がない限りはカスタムオートマッチメイキング方式など、別の方式を使用することをおすすめします。

ギャザリングプールを作成する

まずは、マッチメイキングが成立した後で GS2-Realtime と連携するために、GS2-Realtime の初期設定を行います。

GS2マネージメントコンソールの GS2-Realtime から新しいギャザリングプールを作成します。

../../../../_images/step-00015.png

『ギャザリングプールの新規作成』をクリックします。

../../../../_images/step-00025.png

ギャザリングプールの名前や説明を記入し『作成』ボタンをクリックします。

これで GS2-Realtime が利用できる状態になりました。

マッチメイキングを作成する

GS2マネージメントコンソールの GS2-Matchmaking から新しくマッチメイキングを作成します。

../../../../_images/step-00034.png

『マッチメイキングの新規作成』をクリックします。

../../../../_images/step-00044.png

マッチメイキングの名前をつけて、種類に『ルーム』を指定します。

プレイヤー数 はマッチメイキングを成立させたい人数を指定します。

サービスクラスは想定されるアクセス数に応じたサイズを選択します。

マッチメイキングを成立時の挙動は『GS2-Realtime との自動連携』を選択します。

任意の方式でリアルタイム通信を実現したい場合は『独自サーバでのハンドリング』を選択することで、

マッチメイキング成立時に任意のURLに通知することができるようになります。

ギャザリングプールには先程作成した GS2-Realtime のギャザリングプールの名前を指定します。

これで、マッチメイキング成立時に自動的に GS2-Realtime と連携されゲームサーバが起動するようになります。

これで、GS2マネージメントコンソールでおこなう準備は完了です。

マッチメイキング処理を実装する

ここからは Unity での実装になります。

まずはログイン処理を実装する必要があります。ログインして Gs2.GameSession を取得するまでの手順は GS2-Auth をご参照ください。

ここからはログインが完了している前提で説明を進めます。

ルーム(ギャザリング)を作成する

gs2.Matchmaking.Room.Create() でギャザリングを作成します。

この処理はキューに積まれ、実際の処理は Dispatch() で行われます。

ルーム(ギャザリング)一覧を取得する

gs2.Matchmaking.Room.List() でプレイヤーを募集しているギャザリング一覧を取得します。

この処理はコルーチンで呼び出すことでブロックせずに処理を実行することが出来ます。

ルーム(ギャザリング)に参加する

gs2.Matchmaking.Room.Join() でギャザリングに参加します。

この処理はキューに積まれ、実際の処理は Dispatch() で行われます。

マッチメイキング処理を行う

gs2.Matchmaking.Room.Dispatch() でマッチメイキング処理を実行します。

この処理はマッチメイキング開始後、マッチメイキングが完了するまで毎フレーム呼び出すようにしてください。

この処理はコルーチンで呼び出すことでブロックせずに処理を実行することが出来ます。

実装サンプル

GS2-Matchmaking のSDKはイベントハンドラ方式とコールバック方式の2種類のアプローチで実装することが出来ます。

イベントハンドラ方式

ルームオーナー

public class GameLogic : MonoBehaviour {

    private const string CLIENT_ID = "your client id";
    private const string CLIENT_SECRET = "your client secret";

    private const string MATCHMAKING_NAME = "matchmaking-0004";

    Gs2.Client gs2;
    Gs2.GameSession session;
    bool started;
    public static Gs2.Matchmaking.Gathering gathering;

    void Start () {
        // GS2 Client を初期化
        gs2 = new Gs2.Client (new Gs2.Profile ()
            .ClientId (CLIENT_ID)
            .ClientSecret (CLIENT_SECRET));

        StartCoroutine (Login ());
    }

    IEnumerator Login() {
        // GS2-Account を利用して認証します
        string GAME_NAME = "game-0001";
        string KEY_NAME = "account";
        string USER_ID = "user";
        string PASSWORD = "password";
        string authenticationToken = null;
        yield return gs2.Account.Authentication (
            result => {
                if(result.Error != null) throw result.Error;
                authenticationToken = result.Result;
            },
            GAME_NAME,
            KEY_NAME,
            USER_ID,
            PASSWORD);

        // GS2-Account の認証情報を利用して GS2 にログインします
        yield return gs2.Auth.Login (
            result => {
                if(result.Error != null) throw result.Error;
                session = result.Result;
            },
            USER_ID,
            KEY_NAME,
            authenticationToken);

        StartCoroutine (CreateGathering ());
    }

    IEnumerator CreateGathering() {
        // ルーム(ギャザリング)を作成する
        Gs2.Matchmaking.RoomMatchmakingConfig config =
            new Gs2.Matchmaking.RoomMatchmakingConfig ()
                .MatchmakingName (MATCHMAKING_NAME)        // GS2-Matchmaking に作成したマッチメイキング名
                .Handler(new EventHandler());              // イベントハンドラ
        gs2.Matchmaking.Room.Create (
            session,
            config,
            "enjoy game");        // 作成するルームに付加するメタデータ。ギャザリングに募集条件などを持たせることが出来ます。
        started = true;
    }

    void Update () {
        if (started && gathering == null) {
            // マッチメイキングを開始しており、マッチメイキングが完了していない間呼び出す
            StartCoroutine (DoMatchmaking ());
        }
    }

    IEnumerator DoMatchmaking() {
        // マッチメイキング処理を実行する
        yield return gs2.Matchmaking.Room.Dispatch (
            result => {
                if(result.Error != null) throw result.Error;
                // イベントハンドラ方式では、ここのコールバックは例外ハンドリング以外に使用する必要はありません
            },
            session);
    }
}

public class EventHandler : Gs2.Matchmaking.RoomMatchmakingEventHandler
{
    public void Create (string gatheringId)
    {
        // ギャザリングの作成が完了したときに呼び出されます
        Debug.Log ("作成したギャザリングID: " + gatheringId);
    }

    public void Join (string gatheringId)
    {
        // ギャザリングへの参加が完了したときに呼び出されます
        Debug.Log ("参加したギャザリングID: " + gatheringId);
    }

    public void UpdateStatus (string[] joinedUserIds)
    {
        // 参加ユーザに変動があったときに呼び出されます
        Debug.Log ("[参加者]");
        foreach (string joinedUserId in joinedUserIds) {
            Debug.Log (joinedUserId);
        }
    }

    public void Complete(Gs2.Matchmaking.Gathering gathering)
    {
        // マッチメイキングが成立したときに呼び出されます
        Debug.Log ("GS2-Realtime のゲームサーバ情報: " + gathering.Host + ":" + gathering.Port);
        Debug.Log ("ゲームサーバとの通信に利用する暗号鍵: " + gathering.Secret);
        Debug.Log ("マッチメイキングされた通信相手");
        foreach (string joinedUserId in gathering.JoinedUserIds) {
            Debug.Log (joinedUserId);
        }
        GameLogic.gathering = gathering;
    }

    public void CancelAccept()
    {
        // マッチメイキングのキャンセルがサーバに受理されたときに呼び出されます
    }

    public void Failed(Gs2.Matchmaking.ErrorReason reason)
    {
        // 何らかの理由によりマッチメイキングが失敗したときに呼び出されます
        Debug.Log ("失敗理由: " + reason);
    }
}

ルーム参加

public class GameLogic : MonoBehaviour {

    private const string CLIENT_ID = "your client id";
    private const string CLIENT_SECRET = "your client secret";

    private const string MATCHMAKING_NAME = "matchmaking-0004";

    Gs2.Client gs2;
    Gs2.GameSession session;
    Gs2.Matchmaking.RoomMatchmakingConfig config;
    bool started;
    public static Gs2.Matchmaking.Gathering gathering;

    void Start () {
        // GS2 Client を初期化
        gs2 = new Gs2.Client (new Gs2.Profile ()
            .ClientId (CLIENT_ID)
            .ClientSecret (CLIENT_SECRET));

        StartCoroutine (Login ());
    }

    IEnumerator Login() {
        // GS2-Account を利用して認証します
        string GAME_NAME = "game-0001";
        string KEY_NAME = "account";
        string USER_ID = "user";
        string PASSWORD = "password";
        string authenticationToken = null;
        yield return gs2.Account.Authentication (
            result => {
                if(result.Error != null) throw result.Error;
                authenticationToken = result.Result;
            } ,
            GAME_NAME,
            KEY_NAME,
            USER_ID,
            PASSWORD);

        // GS2-Account の認証情報を利用して GS2 にログインします
        yield return gs2.Auth.Login (
            result => {
                if(result.Error != null) throw result.Error;
                session = result.Result;
            } ,
            USER_ID,
            KEY_NAME,
            authenticationToken);

        StartCoroutine (DescribeGathering ());
    }

    IEnumerator DescribeGathering() {
        // ルーム(ギャザリング)一覧を取得する
        Gs2.Matchmaking.Gathering joinGathering = null;
        config =
            new Gs2.Matchmaking.RoomMatchmakingConfig ()
                .MatchmakingName (MATCHMAKING_NAME)        // GS2-Matchmaking に作成したマッチメイキング名
                .Handler(new EventHandler());              // イベントハンドラ
        yield return gs2.Matchmaking.Room.List(
            result => {
                if(result.Error != null) throw result.Error;
                // 参加するギャザリングを選択する
                joinGathering = result.Result.Gatherings[0];

                // 2ページ目以降が存在する場合はページングトークン情報が格納されています
                // すべてのメッセージの取得が完了している場合は null が設定されています
                string nextPageToken = result.Result.NextPageToken;
            },
            session,           // GS2 のログインセッション
            config,            // マッチメイキング設定
            10,                // ギャザリングの最大取得件数
            null);             // 2ページ目以降を取得する場合にページングトークンを指定します(省略可・省略時は1ページ目を取得)

        StartCoroutine (JoinGathering (joinGathering));
    }

    IEnumerator JoinGathering(Gs2.Matchmaking.Gathering joinGathering) {
        // ギャザリングに参加する
        gs2.Matchmaking.Room.Join (session, config, joinGathering);
        started = true;
    }

    void Update () {
        if (started && gathering == null) {
            // マッチメイキングを開始しており、マッチメイキングが完了していない間呼び出す
            StartCoroutine (DoMatchmaking ());
        }
    }

    IEnumerator DoMatchmaking() {
        // マッチメイキング処理を実行する
        yield return gs2.Matchmaking.Room.Dispatch (
            result => {
                if(result.Error != null) throw result.Error;
                // イベントハンドラ方式では、ここのコールバックは例外ハンドリング以外に使用する必要はありません
            } ,
            session);
    }
}

public class EventHandler : Gs2.Matchmaking.RoomMatchmakingEventHandler
{
    public void Create (string gatheringId)
    {
        // ギャザリングの作成が完了したときに呼び出されます
        Debug.Log ("作成したギャザリングID: " + gatheringId);
    }

    public void Join (string gatheringId)
    {
        // ギャザリングへの参加が完了したときに呼び出されます
        Debug.Log ("参加したギャザリングID: " + gatheringId);
    }

    public void UpdateStatus (string[] joinedUserIds)
    {
        // 参加ユーザに変動があったときに呼び出されます
        Debug.Log ("[参加者]");
        foreach (string joinedUserId in joinedUserIds) {
            Debug.Log (joinedUserId);
        }
    }

    public void Complete(Gs2.Matchmaking.Gathering gathering)
    {
        // マッチメイキングが成立したときに呼び出されます
        Debug.Log ("GS2-Realtime のゲームサーバ情報: " + gathering.Host + ":" + gathering.Port);
        Debug.Log ("ゲームサーバとの通信に利用する暗号鍵: " + gathering.Secret);
        Debug.Log ("マッチメイキングされた通信相手");
        foreach (string joinedUserId in gathering.JoinedUserIds) {
            Debug.Log (joinedUserId);
        }
        GameLogic.gathering = gathering;
    }

    public void CancelAccept()
    {
        // マッチメイキングのキャンセルがサーバに受理されたときに呼び出されます
    }

    public void Failed(Gs2.Matchmaking.ErrorReason reason)
    {
        // 何らかの理由によりマッチメイキングが失敗したときに呼び出されます
        Debug.Log ("失敗理由: " + reason);
    }
}

コールバック方式

イベントハンドラ方式では処理があちこちに分散してしまって好みではない。という開発者向けにコールバック方式の実装方式も提供しています。

ルームオーナー

public class GameLogic : MonoBehaviour {

    private const string CLIENT_ID = "your client id";
    private const string CLIENT_SECRET = "your client secret";

    private const string MATCHMAKING_NAME = "matchmaking-0004";

    Gs2.Client gs2;
    Gs2.GameSession session;
    bool started;
    public static Gs2.Matchmaking.Gathering gathering;

    void Start () {
        // GS2 Client を初期化
        gs2 = new Gs2.Client (new Gs2.Profile ()
            .ClientId (CLIENT_ID)
            .ClientSecret (CLIENT_SECRET));

        StartCoroutine (Login ());
    }

    IEnumerator Login() {
        // GS2-Account を利用して認証します
        string GAME_NAME = "game-0001";
        string KEY_NAME = "account";
        string USER_ID = "user";
        string PASSWORD = "password";
        string authenticationToken = null;
        yield return gs2.Account.Authentication (
            result => {
                if(result.Error != null) throw result.Error;
                authenticationToken = result.Result;
            },
            GAME_NAME,
            KEY_NAME,
            USER_ID,
            PASSWORD);

        // GS2-Account の認証情報を利用して GS2 にログインします
        yield return gs2.Auth.Login (
            result => {
                if(result.Error != null) throw result.Error;
                session = result.Result;
            },
            USER_ID,
            KEY_NAME,
            authenticationToken);

        StartCoroutine (CreateGathering ());
    }

    IEnumerator CreateGathering() {
        // ルーム(ギャザリング)を作成する
        Gs2.Matchmaking.RoomMatchmakingConfig config =
            new Gs2.Matchmaking.RoomMatchmakingConfig ()
                .MatchmakingName (MATCHMAKING_NAME);        // GS2-Matchmaking に作成したマッチメイキング名
        gs2.Matchmaking.Room.Create (
            session,
            config,
            "enjoy game");        // 作成するルームに付加するメタデータ。ギャザリングに募集条件などを持たせることが出来ます。
        started = true;
    }

    void Update () {
        if (started && gathering == null) {
            // マッチメイキングを開始しており、マッチメイキングが完了していない間呼び出す
            StartCoroutine (DoMatchmaking ());
        }
    }

    IEnumerator DoMatchmaking() {
        // マッチメイキング処理を実行する
        yield return gs2.Matchmaking.Room.Dispatch (
            result => {
                if(result.Error != null) throw result.Error;
                // イベントハンドラ方式と異なり、このコールバックで発生したイベントをハンドリングします
                Gs2.Matchmaking.RoomEvent mmEvent = result.Result;
                if(mmEvent != null) {
                    switch(mmEvent.Type) {
                    case Gs2.Matchmaking.EventType.CREATE:
                        // ギャザリングの作成が完了したときに呼び出されます
                        Debug.Log ("作成したギャザリング: " + mmEvent.GatheringId);
                        break;
                    case Gs2.Matchmaking.EventType.JOIN:
                        // ギャザリングへの参加が完了したときに呼び出されます
                        Debug.Log ("参加したギャザリングID: " + mmEvent.GatheringId);
                        break;
                    case Gs2.Matchmaking.EventType.UPDATE_STATUS:
                        // 参加ユーザに変動があったときに返されます
                        Debug.Log ("[参加者]");
                        foreach (string joinedUserId in mmEvent.JoinedUserIds) {
                            Debug.Log (joinedUserId);
                        }
                        break;
                    case Gs2.Matchmaking.EventType.COMPLETE:
                        // マッチメイキングが成立したときに返されます
                        Debug.Log ("GS2-Realtime のゲームサーバ情報: " + gathering.Host + ":" + gathering.Port);
                        Debug.Log ("ゲームサーバとの通信に利用する暗号鍵: " + gathering.Secret);
                        Debug.Log ("マッチメイキングされた通信相手");
                        foreach (string joinedUserId in gathering.JoinedUserIds) {
                            Debug.Log (joinedUserId);
                        }
                        gathering = mmEvent.Gathering;
                        break;
                    case Gs2.Matchmaking.EventType.CANCEL_ACCEPT:
                        // マッチメイキングのキャンセルがサーバに受理されたときに返されます
                        break;
                    case Gs2.Matchmaking.EventType.FAILED:
                        // 何らかの理由によりマッチメイキングが失敗したときに返されます
                        Debug.Log ("失敗理由: " + mmEvent.Reason);
                        break;
                    }
                }
            },
            session);
    }
}

ルーム参加

public class GameLogic : MonoBehaviour {

    private const string CLIENT_ID = "your client id";
    private const string CLIENT_SECRET = "your client secret";

    private const string MATCHMAKING_NAME = "matchmaking-0004";

    Gs2.Client gs2;
    Gs2.GameSession session;
    Gs2.Matchmaking.RoomMatchmakingConfig config;
    bool started;
    public static Gs2.Matchmaking.Gathering gathering;

    void Start () {
        // GS2 Client を初期化
        gs2 = new Gs2.Client (new Gs2.Profile ()
            .ClientId (CLIENT_ID)
            .ClientSecret (CLIENT_SECRET));

        StartCoroutine (Login ());
    }

    IEnumerator Login() {
        // GS2-Account を利用して認証します
        string GAME_NAME = "game-0001";
        string KEY_NAME = "account";
        string USER_ID = "user";
        string PASSWORD = "password";
        string authenticationToken = null;
        yield return gs2.Account.Authentication (
            result => {
                if(result.Error != null) throw result.Error;
                authenticationToken = result.Result;
            } ,
            GAME_NAME,
            KEY_NAME,
            USER_ID,
            PASSWORD);

        // GS2-Account の認証情報を利用して GS2 にログインします
        yield return gs2.Auth.Login (
            result => {
                if(result.Error != null) throw result.Error;
                session = result.Result;
            } ,
            USER_ID,
            KEY_NAME,
            authenticationToken);

        StartCoroutine (DescribeGathering ());
    }

    IEnumerator DescribeGathering() {
        // ルーム(ギャザリング)一覧を取得する
        Gs2.Matchmaking.Gathering joinGathering = null;
        config =
            new Gs2.Matchmaking.RoomMatchmakingConfig ()
                .MatchmakingName (MATCHMAKING_NAME)        // GS2-Matchmaking に作成したマッチメイキング名
        yield return gs2.Matchmaking.Room.List(
            result => {
                if(result.Error != null) throw result.Error;
                // 参加するギャザリングを選択する
                joinGathering = result.Result.Gatherings[0];

                // 2ページ目以降が存在する場合はページングトークン情報が格納されています
                // すべてのメッセージの取得が完了している場合は null が設定されています
                string nextPageToken = result.Result.NextPageToken;
            },
            session,           // GS2 のログインセッション
            config,            // マッチメイキング設定
            10,                // ギャザリングの最大取得件数
            null);             // 2ページ目以降を取得する場合にページングトークンを指定します(省略可・省略時は1ページ目を取得)

        StartCoroutine (JoinGathering (joinGathering));
    }

    IEnumerator JoinGathering(Gs2.Matchmaking.Gathering joinGathering) {
        // ギャザリングに参加する
        gs2.Matchmaking.Room.Join (session, config, joinGathering);
        started = true;
    }

    void Update () {
        if (started && gathering == null) {
            // マッチメイキングを開始しており、マッチメイキングが完了していない間呼び出す
            StartCoroutine (DoMatchmaking ());
        }
    }

    IEnumerator DoMatchmaking() {
        // マッチメイキング処理を実行する
        yield return gs2.Matchmaking.Room.Dispatch (
            result => {
                if(result.Error != null) throw result.Error;
                // イベントハンドラ方式と異なり、このコールバックで発生したイベントをハンドリングします
                Gs2.Matchmaking.RoomEvent mmEvent = result.Result;
                if(mmEvent != null) {
                    switch(mmEvent.Type) {
                    case Gs2.Matchmaking.EventType.CREATE:
                        // ギャザリングの作成が完了したときに呼び出されます
                        Debug.Log ("作成したギャザリング: " + mmEvent.GatheringId);
                        break;
                    case Gs2.Matchmaking.EventType.JOIN:
                        // ギャザリングへの参加が完了したときに呼び出されます
                        Debug.Log ("参加したギャザリングID: " + mmEvent.GatheringId);
                        break;
                    case Gs2.Matchmaking.EventType.UPDATE_STATUS:
                        // 参加ユーザに変動があったときに返されます
                        Debug.Log ("[参加者]");
                        foreach (string joinedUserId in mmEvent.JoinedUserIds) {
                            Debug.Log (joinedUserId);
                        }
                        break;
                    case Gs2.Matchmaking.EventType.COMPLETE:
                        // マッチメイキングが成立したときに返されます
                        Debug.Log ("GS2-Realtime のゲームサーバ情報: " + gathering.Host + ":" + gathering.Port);
                        Debug.Log ("ゲームサーバとの通信に利用する暗号鍵: " + gathering.Secret);
                        Debug.Log ("マッチメイキングされた通信相手");
                        foreach (string joinedUserId in gathering.JoinedUserIds) {
                            Debug.Log (joinedUserId);
                        }
                        gathering = mmEvent.Gathering;
                        break;
                    case Gs2.Matchmaking.EventType.CANCEL_ACCEPT:
                        // マッチメイキングのキャンセルがサーバに受理されたときに返されます
                        break;
                    case Gs2.Matchmaking.EventType.FAILED:
                        // 何らかの理由によりマッチメイキングが失敗したときに返されます
                        Debug.Log ("失敗理由: " + mmEvent.Reason);
                        break;
                    }
                }
            } ,
            session);
    }
}

どちらの方式を採用しても同じように マッチメイキング機能を利用することが出来ます。

マッチメイキングが成立したら、 GS2-Realtime を利用して対戦や協力プレイの実装を進めることになります。