[Unity,Photon]Photon2で自動更新されるルームのリストを作る

#Photon2で下画像のようなルームリストを作りたい

前回の続きになります。
前回：[[Unity,Photon2]Photon2でルームを作成したい](https://qiita.com/yukienko/items/55cce7ccd67a5c77cdbb)

こんな感じで選択したボタンを押したらそのルームに入りたい。
今回はそのボタンを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272154/2fcecf14-800c-76f7-dea3-ca9a0c8c51c9.png)


## 表示させるボタン
今回使ったボタンのプレハブの構成はこんな感じです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272154/d26787b2-1d33-666f-241b-6c8735476fe4.png)
ボタンには押されたらボタンの中で表示されているRoomNameのルームに移動するという処理だけです。
調べたらいくらでも出てくるので割愛。

## ボタンを生成、情報を入力
今回はボタンを並べたかったのでScroolView内のContentにボタンを生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272154/bb4fab1c-613b-a86a-fcdd-85d7deaa4ad2.png)
デフォルトから名前を変更した"RoomContet"に"ViewMatchWaitingPlayers.cs"というスクリプトを追加します。

## ViewMatchWaitingPlayers.csの構成
```C#:ViewMatchWaitingPlayers.cs
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine.UI;

 public class ViewMatchWaitingPlayers : MonoBehaviourPunCallbacks
{
    public GameObject RoomButton;

    public void Start()
    {
        //ロビーへ移動する
        PhotonNetwork.JoinLobby();
    }

    //ルームに動きがあった場合
    public override void OnRoomListUpdate(List<RoomInfo> roomList)
    {
        Debug.Log("[function]ReloadRooms");
        foreach(RoomInfo r in roomList)
        {
            //プレイヤーが存在しているルーム
            if (r.PlayerCount > 0)
            {
                RoomButtonCreate(r);
            }
            else
            {
                RoomButtonDelete(r);
            }
        }
    }

    //ルームボタンの作成
    public void RoomButtonCreate(RoomInfo r)
    {
        //すでに存在していたのなら情報の更新
        if (gameObject.transform.Find(r.Name))
        {
            RoomInfoUpdate(gameObject.transform.Find(r.Name).gameObject, r);
        }
        //新しく作られたルームならばボタンの作成
        else
        {
            var roomButton = (GameObject)Instantiate(RoomButton);
            roomButton.transform.SetParent(gameObject.transform, false);
            RoomInfoUpdate(roomButton, r);
            //生成したボタンの名前を作成するルームの名前にする
            roomButton.name = r.Name;
        }
    }

    //ルームボタンの削除
    public void RoomButtonDelete(RoomInfo r)
    {
        //ボタンが存在すれば削除
        if (gameObject.transform.Find(r.Name))
        {
            GameObject.Destroy(gameObject.transform.Find(r.Name).gameObject);
        }
    }

    //ルームボタンのInfoの更新
    public void RoomInfoUpdate(GameObject button, RoomInfo info)
    {
        foreach (Text t in button.GetComponentsInChildren<Text>())
        {
            if (t.name == "RoomName")
            {
                t.text = info.Name;
            }
            else if (t.name == "MaxPLayerCount")
            {
                t.text = info.MaxPlayers.ToString();
            }
            else if (t.name == "RoomInPlayerCount")
            {
                t.text = info.PlayerCount.ToString();
            }
        }
    }
}
```

このコードの簡単な解説です

##ルームの取得方法
```C#:

public GameObject RoomButton;

public void Start()
    {
        //ロビーへ移動する
        PhotonNetwork.JoinLobby();
    }
```

public GameObjectで先ほど作成しておいたボタンのプレハブを指定します。

**ロビーにいないとルーム情報を取得できない**のでロビーに入っておきます。

```C#:

public override void OnRoomListUpdate(List<RoomInfo> roomList)
    {
        foreach(RoomInfo r in roomList)
        {
            //プレイヤーが存在しているルーム
            if (r.PlayerCount > 0)
            {
                RoomButtonCreate(r);
            }
            else
            {
                RoomButtonDelete(r);
            }
        }
    }
```

この"OnRoomListUpdate()"でルーム情報を取得します。
自分はここで詰まってたのですが、この関数はルーム内で人数が変更されたり、ルームの情報が変更されたとき**のみ**、
変更が起こったルーム**だけ**roomListに入ります。
任意のタイミングでは実行できません。

ルームのリスト全部じゃないんかーい。好きなタイミングで呼び出せんのかーいって感じですが、仕様ならしょうがないです。

ちなみに、
ロビーに入ったときは何もない状態から"OnRoomListUpdate"を読み込む形になるのでルームが存在すればすべてのルームがroomListに入ります。
それ以降は先ほどと同じで人数が変わったなどの変更があったルームだけがroomListとして"OnRoomListUpdate()"が実行されます。

とりあえずこれでルームが取得できました。次はこのルーム情報をもとにプレハブのボタンに情報を表示させてボタンを生成していきます。

##ルーム情報を可視化
"OnRoomListUpdate()"で更新があったルームリストがくるので、
そのリストの中のルームにプレイヤーがいる =　人数制限だとしても表示させるとしたら表示する。
なので、
プレイヤーが存在していたらボタンを作成していく方向で行きます。

```C#
public void RoomButtonCreate(RoomInfo r)
    {
        //すでに存在していたのなら情報の更新
        if (gameObject.transform.Find(r.Name))
        {
            RoomInfoUpdate(gameObject.transform.Find(r.Name).gameObject, r);
        }
        //新しく作られたルームならばボタンの作成
        else
        {
            var roomButton = (GameObject)Instantiate(RoomButton);
            roomButton.transform.SetParent(gameObject.transform, false);
            RoomInfoUpdate(roomButton, r);
            //生成したボタンの名前を作成するルームの名前にする
            roomButton.name = r.Name;
        }
    }

public void RoomInfoUpdate(GameObject button, RoomInfo info)
    {
        foreach (Text t in button.GetComponentsInChildren<Text>())
        {
            if (t.name == "RoomName")
            {
                t.text = info.Name;
            }
            else if (t.name == "MaxPLayerCount")
            {
                t.text = info.MaxPlayers.ToString();
            }
            else if (t.name == "RoomInPlayerCount")
            {
                t.text = info.PlayerCount.ToString();
            }
        }
    }
```

ルームの情報が更新されるたびに"OnRoomListUpdate()"が実行されるので
すでに存在しているルームならば情報の更新だけにしておきます。そうしないと人が抜けたり入ったりするだけで同じルームのボタンがいくつも生成されてしまいます。

これで生成したボタンに情報が入るようになります。

##ルームが消えたらルームのボタンを消す

```C#
public void RoomButtonDelete(RoomInfo r)
    {
        //ボタンが存在すれば削除
        if (gameObject.transform.Find(r.Name))
        {
            GameObject.Destroy(gameObject.transform.Find(r.Name).gameObject);
        }
    }
```

人がいないルームをいつまでも表示させておくわけにはいかないので人が0人になったらボタンのリストから削除します。

これで冒頭にもあったルームリストが作成できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/272154/2fcecf14-800c-76f7-dea3-ca9a0c8c51c9.png)

##おわり
ルーム情報の取得は**public override void OnRoomListUpdate(List<RoomInfo> roomList)**
public override void OnRoomListUpdate(List<RoomInfo> roomList)を使うためには**ロビーに入っておく**
roomListには**変更があったルームの情報しか入らない**