Unityでオンラインマルチプレイなゲームを作りたい その6 ルーム入室

[前回の記事](https://qiita.com/koyuki2007/items/b537549767d003ac96e4)でルームの作成が行えるようになりました。
今回は作成されたルームへ入室を行う処理を作っていきます。

# 今回の目標
![Untitled Diagram_4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469983/76aedcec-09f3-6fd3-2382-cff3632cf3cb.png)
赤〇で囲っている部分を作ります。

イメージ図
※ルーム名は気にしないでください。
![キャプチャ6.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/469983/8e7daec1-5940-4815-6620-66013cc3d213.jpeg)
ルームリストから選んで入室を行うものと、プライベート設定になっている部屋を指定して入室を行うものの2パターンを実装しています。

# ルームリストから入室
http://www.monobitengine.com/doc/mun/contents/FeatureClient/JoinRoom.htm

```c#
MonobitEngine.MonobitNetwork.JoinRoom("roomName");
```
引数に入室したいルーム名を入力して使用するだけで任意のルームへ入室できます。

http://www.monobitengine.com/doc/mun/contents/FeatureClient/GetRoomData.htm

```c#
MonobitEngine.MonobitNetwork.GetRoomData()
```
入室可能なルーム群をRoomData[]型で取得できます。

<code>MonobitEngine.MonobitNetwork.GetRoomData</code>で取得したものをリストとして表示し、選択したルームからルーム名取得し<code>MonobitEngine.MonobitNetwork.JoinRoom</code>の引数に入れてあげるという形で実装していきます。

まず、ルームリストに並べるボタンを作ります。

```c#:ScrollViewButton.cs
   /// <summary></summary>
    public class ScrollViewButton : UnityEngine.MonoBehaviour
    {
        /// <summary></summary>
        private RoomData m_Data;

        /// <summary>ボタンにルーム情報を適用する</summary>
        /// <param name="roomData">ボタンに適用させたいルームの情報</param>
        public void Set(RoomData roomData)
        {
            m_Data = roomData;

            gameObject.GetComponent<Button>().onClick.AddListener(OnClick);
            gameObject.GetComponentInChildren<Text>().text = m_Data.name + ", " + m_Data.playerCount + "/4";
        }

        /// <summary>ボタンクリック時に適用されたルーム情報を元に任ルームへ入室する</summary>
        private void OnClick()
        {
            MonobitNetwork.JoinRoom(m_Data.name);
        }
    }
```
uGUIのボタンをプレハブ化したものにアタッチして使ってください。
ルームリストに表示する際にルームデータを貰い、クリックされたときに貰ったルームデータを元に入室を行うようにしています。

次にボタンを並べるリストを作ります。
※リスト内に表示するボタンの位置調整などの処理は省いています。

```c#:ScrollView.cs
    /// <summary>ルームリスト及びボタンを表示するスクロールビュー</summary>
    public class ScrollView : UnityEngine.MonoBehaviour
    {
        /// <summary>ルームリストに表示するボタンのプレハブ</summary>
        private GameObject m_ButtonPrefub;

        /// <summary>ルームリストに表示するボタンのオブジェクトのリスト</summary>
        private List<GameObject> m_ButtonsList;

        // Start is called before the first frame update
        void Start()
        {
            m_ButtonPrefub = Resources.Load("UI_ScrollViewButton") as GameObject;

            m_ButtonsList = new List<GameObject>();

            UpdateRoomData();
        }

        /// <summary>ルームリストを更新する</summary>
        public void UpdateRoomData()
        {
            int roomCount = MonobitNetwork.GetRoomData().Length;
            for (int i = 0; i < roomCount; i++)
            {
                RoomData roomData = MonobitNetwork.GetRoomData()[i];

                // パスワードが設定されている = 非公開ルームとして扱うのでリスト表示から除外
                if (!roomData.customParameters["password"].Equals("empty")) { continue; }

                // リスト上に並べるボタンを生成
                GameObject button = (GameObject)Instantiate(m_ButtonPrefub);

                // ボタンにルーム情報を適用する
                button.GetComponent<ScrollViewButton>().Set(MonobitNetwork.GetRoomData()[i]);

                m_ButtonsList.Add(button);
            }
        }

        /// <summary>ルームリストを削除する</summary>
        public void DestroyAll()
        {
            int length = m_ButtonsList.Count;

            for (int i = 0; i < length; ++i)
            {
                if(m_ButtonsList[i] == null) { continue; }

                Destroy(m_ButtonsList[i]);
            }

            m_ButtonsList.Clear();
            m_ButtonsList.TrimExcess();
        }
    }
```
<code>public void UpdateRoomData()</code>がメインの処理になります。
これでルームリストにルーム情報が設定されたボタンが並べられます。
ボタンを押すと適用されたルームへ入室してくれます。

```c#
/// <summary></summary>
private void OnClickUpdateRoomList()
{
    ScrollView scrollView = m_ScrollViewObj.GetComponent<ScrollView>();

    scrollView.DestroyAll();

    scrollView.UpdateRoomData();
}
```
更新ボタンを作り、このようにしてルームリストの情報を任意で更新するようにするといいですね。

# プライベート設定にしている部屋への入室
ルームリストを作ったときと同様で、<code>MonobitEngine.MonobitNetwork.JoinRoom</code>と<code>MonobitEngine.MonobitNetwork.GetRoomData</code>を使い実装していきます。

```c#:SceneJoinRoom.cs
public class SceneJoinRoom : MonobitEngine.MonoBehaviour
{
    /// <summary>ルーム名</summary>
    private string m_RoomName = string.Empty;

    /// <summary>パスワード</summary>
    private string m_Password = string.Empty;

    // Start is called before the first frame update
    void Start()
    {
        if (!MonobitNetwork.inLobby) { Debug.Log("Not in lobby"); }

       /******** 表示するuGUIの初期化/配置等の処理 ******/
    }

    /// <summary>ルーム名入力時に呼ばれる</summary>
    /// <param name="roomName">入力された文字列</param>
    private void OnInputRoomName(string roomName)
    {
        m_RoomName = roomName;
    }

    /// <summary>パスワード入力痔に呼ばれる</summary>
    /// <param name="password">入力された文字列</param>
    private void OnInputPassword(string password)
    {
        m_Password = password;
    }

    /// <summary>作成ボタンが押された際に呼ばれる</summary>
    private void OnClickJoin()
    {
        RoomData[] roomData = MonobitNetwork.GetRoomData();

        int length = roomData.Length;
        for (int i = 0; i < length; ++i)
        {
            // 入りたいルームの名前に該当するルームを探し出す
            if (!roomData[i].name.Equals(m_RoomName)) { continue; }

            // 入りたいルームに設定されているパスワードを入力したパスワードと一致するかを確認する
            if (!roomData[i].customParameters["password"].Equals(m_Password))
            {
                Debug.Log("Incorrect Password ");

                return;
            }

            MonobitNetwork.JoinRoom(m_RoomName);

            break;
        }
    }
}
```
プライベート設定になっている入りたいルームの名前を<code>MonobitEngine.MonobitNetwork.GetRoomData</code>で取得したルーム一覧から探し出し、見つかったルームに設定されているパスワードを、入力されたパスワードが一致するかを確認しています。
これで、パスワード設定がされた非公開ルームへの入室が実装できました。

仕上げにルーム入室時/失敗時/サーバー切断時のコールバックを実装していきます。
http://www.monobitengine.com/doc/mun/contents/FeatureClient/CallbackFunction.htm#OnJoinedRoom%20%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89

```c#
public void OnJoinedRoom()
```
ルーム入室に成功した際に呼ばれます。

http://www.monobitengine.com/doc/mun/contents/FeatureClient/CallbackFunction.htm#OnJoinRoomFailed%20%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89

```c#
public void OnJoinRoomFailed(object[] codeAndMsg)
```
ルーム入室に失敗した際に呼ばれます。

コードにコールバックを追加します。

```c#:SceneJoinRoom.cs
public class SceneJoinRoom : MonobitEngine.MonoBehaviour
{
    /// <summary>ルーム名</summary>
    private string m_RoomName = string.Empty;

    /// <summary>パスワード</summary>
    private string m_Password = string.Empty;

    // Start is called before the first frame update
    void Start()
    {
        if (!MonobitNetwork.inLobby) { Debug.Log("Not in lobby"); }

       /******** 表示するuGUIの初期化/配置等の処理 ******/
    }

    /// <summary>ルーム入室成功時に呼ばれる</summary>
    private void OnJoinedRoom()
    {
        SceneManager.LoadScene("InGame");
    }

    /// <summary>ルーム入室失敗時に呼ばれる</summary>
    private void OnJoinRoomFailed(object[] codeAndMsg)
    {
        Debug.Log("Join Room Failed : errorCode = " + codeAndMsg[0] + ", message = " + codeAndMsg[1]);
    }

    /// <summary>MUNサーバーとの接続を切った際に呼ばれるコールバック</summary>
    private void OnDisconnectedFromServer()
    {
        SceneManager.LoadScene("Title");
    }

    /// <summary>ルーム名入力時に呼ばれる</summary>
    /// <param name="roomName">入力された文字列</param>
    private void OnInputRoomName(string roomName)
    {
        m_RoomName = roomName;
    }

    /// <summary>パスワード入力痔に呼ばれる</summary>
    /// <param name="password">入力された文字列</param>
    private void OnInputPassword(string password)
    {
        m_Password = password;
    }

    /// <summary>作成ボタンが押された際に呼ばれる</summary>
    private void OnClickJoin()
    {
        RoomData[] roomData = MonobitNetwork.GetRoomData();

        int length = roomData.Length;
        for (int i = 0; i < length; ++i)
        {
            // 入りたいルームの名前に該当するルームを探し出す
            if (!roomData[i].name.Equals(m_RoomName)) { continue; }

            // 入りたいルームに設定されているパスワードを入力したパスワードと一致するかを確認する
            if (!roomData[i].customParameters["password"].Equals(m_Password))
            {
                Debug.Log("Incorrect Password ");

                return;
            }

            MonobitNetwork.JoinRoom(m_RoomName);

            break;
        }
    }
}
```
ルーム入室成功時に次の画面へ遷移するようにしています。
失敗時は失敗内容をログに出力しています。
サーバーが切断された際の処理もついでに追加しています。

これでルーム入室ができるようになりました。
次回はゲーム開始前の、ルーム待機室のようなものを作っていきます。

# 参考
http://www.monobitengine.com/doc/mun/contents/FeatureClient/JoinRoom.htm
http://www.monobitengine.com/doc/mun/contents/FeatureClient/GetRoomData.htm
http://www.monobitengine.com/doc/mun/contents/FeatureClient/CallbackFunction.htm#OnJoinedRoom%20%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89
http://www.monobitengine.com/doc/mun/contents/FeatureClient/CallbackFunction.htm#OnJoinRoomFailed%20%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89