//tips
//PUN遷移修正
ロビーボタンクリックからの同期・遷移を正常に行われるように修正していく。
問題が起こっている箇所を絞り込みたいのでpublic override void OnRoomListUpdate(List<RoomInfo> roomList)のパーツであるelse if (!info.RemovedFromList)から部分的に削除して作動内容を確認していく。
まずはelse if以下を削除する。
else if (!info.RemovedFromList)
{
/*
// リスト要素を追加する
entry = (inactiveEntries.Count > 0)
? inactiveEntries.Pop().SetAsLastSibling() //Pop:inactiveEntriesからデータ取り出し
: Instantiate(roomListEntryPrefab, scrollRect.content);
entry.Activate(info);
activeEntries.Add(info.Name, entry);
*/
}
この部分を削除したら正常に作動する。ボタン生成箇所に問題がありそうだと見当をつけることができる。
OnJoinedRoom()が2回呼ばれてしまう問題は、NetworkManagerBが各ボタンオブジェクトにアタッチされ、ボタンの数だけOnJoinedRoom()が呼ばれることで複数遷移が発生しているものと仮定する。
この問題を解消するには、NetworkManagerBをボタン外のオブジェクトに設置する必要があり、そうするとEnterButtonのOnclickに設定しているJoinOrCreateRoomメソッドが実行できなくなってしまう。
なので、一旦遷移スクリプトをNetworkManagerBではなく、別のスクリプトで生成し直し、prefab外に出すことで対応してみる。
下記のスクリプトをシーンのからオブジェクトにアタッチし、NetworkManagerBスクリプトの該当部分から削除した。
using ExitGames.Client.Photon;
using Photon.Pun;
using Photon.Realtime;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneMove : MonoBehaviourPunCallbacks
{
// 部屋に入室した時
public override void OnJoinedRoom()
{
Debug.Log("SceneMove");
if (PhotonNetwork.CurrentRoom.PlayerCount == 2)
{
Debug.Log("OnJoinedRoomCurrentRoom.PlayerCount");
SceneManager.LoadSceneAsync("SampleScene3", LoadSceneMode.Single);
PhotonNetwork.IsMessageQueueRunning = true;
}
}
}
これにより無事ロビーボタンクリックからの同期・遷移は正常にできるようになった。
ここからはボタンの名前づけによる識別と新規ボタンの生成ボタンを作成していく。
いくつか考えるポイントがあり、Inputfieldからユーザーがメイキングとルームオプションのカスタムプロパティとして設定するものの兼ね合いをどうするか。Directoryリストに追加する名前activeEntries.Add(info.Name, entry);はどうするのか、info.nameはどこで設定されるのかを考えていく必要がある。
// ルームオプションにカスタムプロパティを設定
ExitGames.Client.Photon.Hashtable customRoomProperties = new ExitGames.Client.Photon.Hashtable
{
{ "Stage", stageName },
{ "Difficulty", stageDifficulty }
};
roomOptions.CustomRoomProperties = customRoomProperties;
// ロビーに公開するカスタムプロパティを指定
roomOptions.CustomRoomPropertiesForLobby = new string[] { "Stage", "Difficulty" };
Roomlistに登録されるInfo.nameをinfieldの文言にすることが一番シンプルなので、info.nameの内容を突き止める。
基本的にroomの情報はroom createの時点で情報生成されると思うので、そこから見直してみる。
Roomの名前は
PhotonNetwork.JoinOrCreateRoom("Sample", roomOptions, TypedLobby.Default);
のようにJoinOrCreateRoomの第一項で決まり、下記のような型をとる。
PhotonNetwork.JoinOrCreateRoom
(string roomName, RoomOptions roomOptions, TypedLobby typedLobby)
このroomNameにあたる箇所を変数とし、input field下のroom name Textの内容を代入してみる。
同じprefab内にJoinOrCreateRoomがあるNetworkManagerscriptBとinput fieldがあるので[SerializeField]でinput field下のroom name Textを取得させる。
"Sample”の部分に [SerializeField] Text Buttonname;で取得したTextを代入しようとしたらstringにはtextを代入できないとのエラーが発生。
PhotonNetwork.JoinOrCreateRoom(Buttonname.text.ToString(), roomOptions, TypedLobby.Default);
TextをString型に直してあげた。デバッグで出力を確認すると、
Debug.Log("room"+ Buttonname.text + "に入りました");
の部分がきちんとInputFieldに入力した内容が反映されていた。
ルーム名を自由に変えることができるようになったのでdictionaryに内容を反映できているか確認する必要がある。
ロビーに異なるルームを二つたて、それぞれのルーム名とボタンが紐づいているかdictionaryで確認する。
ボタンを二つに複製し、スタートすると、下記のエラーが生じ、
Operation JoinLobby (229) not called because client is not connected or not ready yet, client state: JoiningLobby
これは各ボタンに紐づけられているNetworkManagerBスクリプトのprivate void JoinLobby()が実行されているため、先ほど分離させたSceneMoveスクリプトに移動させる。
一旦下記の項目を移動させた。
using ExitGames.Client.Photon;
using Photon.Pun;
using Photon.Realtime;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class SceneMove : MonoBehaviourPunCallbacks
{
// Awake
private void Awake()
{
// シーンの自動同期: 無効
PhotonNetwork.AutomaticallySyncScene = false;
}
// Start is called before the first frame update
private void Start()
{
// Photonに接続
Connect("1.0");
Debug.Log("a" + PhotonNetwork.IsMessageQueueRunning);
}
// Connect //////////////////////////////////////////////////////////////////////////
// Photonに接続する
private void Connect(string gameVersion)
{
if (PhotonNetwork.IsConnected == false)
{
PhotonNetwork.GameVersion = gameVersion;
PhotonNetwork.ConnectUsingSettings();
}
}
// ニックネームを付ける
private void SetMyNickName(string nickName)
{
if (PhotonNetwork.IsConnected)
{
PhotonNetwork.LocalPlayer.NickName = nickName;
}
}
// マスターサーバーに接続した時
public override void OnConnectedToMaster()
{
Debug.Log("OnConnectedToMaster");
// ロビーに入る
JoinLobby();
}
// Join Lobby ///////////////////////////////////////////////////////////////////////
// ロビーに入る
private void JoinLobby()
{
if (PhotonNetwork.IsConnected)
{
PhotonNetwork.JoinLobby();
Debug.Log("ロビーに入りました");
}
}
// 部屋に入室した時
public override void OnJoinedRoom()
{
Debug.Log("SceneMove");
if (PhotonNetwork.CurrentRoom.PlayerCount == 2)
{
Debug.Log("OnJoinedRoomCurrentRoom.PlayerCount");
SceneManager.LoadSceneAsync("SampleScene3", LoadSceneMode.Single);
PhotonNetwork.IsMessageQueueRunning = true;
}
}
// Pun Callbacks ////////////////////////////////////////////////////////////////////
// Photonに接続した時
public override void OnConnected()
{
Debug.Log("OnConnected");
// ニックネームを付ける
SetMyNickName("Naki");
}
// Photonから切断された時
public override void OnDisconnected(DisconnectCause cause)
{
Debug.Log("OnDisconnected");
}
}
これでボタンを複製してもエラーは生じなくなっている。
デモと別々の部屋を作成し、入って見たところ、コンソール上では別々の部屋に入れたことがわかる。
activeEntries.Add(info.Name, entry);でdictionaryリストに追加されているため、activeEntriesのリストをデバッグするコードを追加する。
string ActiveList = "";
foreach (string key in activeEntries.Keys)
{
ActiveList = ActiveList + "key=" + key + ",val=" + activeEntries[key] + "/";
//ActiveList +にしたのは、後から追加していく文で表示させるため
}
Debug.Log("ActiveList:"+ActiveList);
public override void OnRoomListUpdate(List<RoomInfo> roomList)の後にアタッチしてしまったら自身の部屋の作成の際には呼ばれないため確認できず、すぐに削除するが臨時でUpdate関数を追加した。
private void Update()
{
string ActiveList = "";
foreach (string key in activeEntries.Keys)
{
ActiveList = ActiveList + "key=" + key + ",val=" + activeEntries[key] + "/";
//ActiveList +にしたのは、後から追加していく文で表示させるため
}
Debug.Log("ActiveList:" + ActiveList);
}
自身がルームBに入った後も、
ActiveList:key=aaa,val=RoomListEntryB(Clone) (InputfieldButton)/
の表示が出続けることからActiveListの役割は、相手側のエントリーのみ認識するものだと理解できた。
現状は相手側のエントリーをからボタンで表示してしまうので、ボタン名付きで表示するにはどうすれば良いかを考えていくことになる。
activeEntriesの役割について再考する必要が出てきた。