//tips
//PUN2 ロビーからルームへの移行検証
そもそもロビー自体が使っているphotonのシステムとルームで使用しているphotonの仕組みがどのようになっているのかを認識していく。
表にして確認すると、ロビーとルームは別のサーバーで動かされることがわかり、同時に、互いの連結にはphoton networkの仕組みをうまく使う必要があることがわかった。
先に作成したルームで同期するオブジェクトの例から仕組みを考えていく。
同期を行ったGamePlayerにはphoton viewコンポーネントが追加され、同期対象とされ、空オブジェクトにアタッチされたSample Sceneスクリプトにサーバーとの関係性を表すスクリプトをアタッチした。
内容としては、MonoBehaviourPunCallbacksを継承することで、Photonのコールバックを受け取れるようにした上で、PhotonServerSettingsに設定した内容を使ってマスターサーバーへ接続。
マスターサーバーへの接続が成功した時に呼ばれるコールバックpublic override void OnConnectedToMaster()で"room"という名前のルームに参加する(ルームが無ければ作成してから参加する)メソッドの追加。
PhotonNetwork.JoinOrCreateRoom("room", new RoomOptions(), TypedLobby.Default);
これをPhotonNetwork.JoinRoomとPhotonNetwork.CreateRoomに分けてメソッド化できれば、ルームボタンにJoinRoomメソッドをonclickに割り当て、add roomのボタンのon clickにCreateRoomメソッドを割り当てれば仕組みとして成立する。
また、ロビーの時点で各プレイヤーのオブジェクトを生成したくないため、マッチングが成功した時に呼ばれるコールバックpublic override void OnJoinedRoom() で、受信メッセージ処理の実行・一時停止を切り替える処理を行う必要がある。
public override void OnJoinedRoom() {
PhotonNetwork.IsMessageQueueRunning = false;
SceneManager.LoadSceneAsync("Game", LoadSceneMode.Single);
}
遷移後のシーンでPhotonNetwork.IsMessageQueueRunningをtrueに戻すことで、他プレイヤーのネットワークオブジェクトが遷移後のシーンに正しく生成されるようになる。
private void Start() {
PhotonNetwork.IsMessageQueueRunning = true;
var v = new Vector3(Random.Range(-3f, 3f), Random.Range(-3f, 3f));
PhotonNetwork.Instantiate("GamePlayer", v, Quaternion.identity);
}
つまり、シーン遷移前と後の二つのシーンでSample Sceneスクリプトは存在している必要がある。
なので、現在のロビーがあるroomシーンに下記スクリプトを追加する。
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.SceneManagement;
// MonoBehaviourではなくMonoBehaviourPunCallbacksを継承して、Photonのコールバックを受け取れるようにする
public class SampleSceneB : MonoBehaviourPunCallbacks
{
private void Start()
{
// PhotonServerSettingsに設定した内容を使ってマスターサーバーへ接続する
PhotonNetwork.ConnectUsingSettings();
}
// マスターサーバーへの接続が成功した時に呼ばれるコールバック
public override void OnConnectedToMaster()
{
// "room1”という名前のルームに参加する(ルームが無ければ作成してから参加する)
PhotonNetwork.JoinOrCreateRoom("room1", new RoomOptions(), TypedLobby.Default);
}
// マッチングが成功した時に呼ばれるコールバック
public override void OnJoinedRoom()
{
PhotonNetwork.IsMessageQueueRunning = false;
SceneManager.LoadSceneAsync("Sample", LoadSceneMode.Single);
}
}
ロービーからルームに遷移することはできたがボタンをクリックする前に遷移してしまうのでこちらを修正する。
ルームシーンのNetworkmanagerスクリプトがsample sceneスクリプトの内容を盛り込んでいるものなので、Networkmanagerにうまく遷移コードを組み込んでいく。
Networkmanagerスクリプトを下記のように追加編集して、ボタンのonclickにpublic void JoinOrCreateRoom()を設定するもエラー。
// 部屋を作成して入室する
if (PhotonNetwork.InLobby)
{
PhotonNetwork.CreateRoom(roomName, roomOptions);
SceneManager.LoadSceneAsync(roomName, LoadSceneMode.Single);
}
// 入室 (存在しなければ部屋を作成して入室する)
if (PhotonNetwork.InLobby)
{
PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
SceneManager.LoadSceneAsync(roomName, LoadSceneMode.Single);
}
エラー内容は、
JoinRoom failed. Client is on GameServer (must be Master Server for matchmaking) and ready. Wait for callback: OnJoinedLobby or OnConnectedToMaster.
UnityEngine.Debug:LogError(Object)
Photon.Pun.PhotonNetwork:JoinRoom(String, String[]) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1791)
RoomListEntry:<Start>b__7_0() (at Assets/RoomListEntry.cs:31)
UnityEngine.EventSystems.EventSystem:Update() (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/EventSystem.cs:377)
マッチングの前にゲームサーバーの方へ移行してしまうのが問題となっているので、シーン遷移コードの前に PhotonNetwork.IsMessageQueueRunning = false;を貼り付ける。
これで実行すると下記が表示される。ルームメイトがいないと部屋に入れないとのこと。
JoinRoom failed. A roomname is required. If you don't know one, how will you join?
UnityEngine.Debug:LogError(Object)
Photon.Pun.PhotonNetwork:JoinRoom(String, String[]) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1796)
RoomListEntry:<Start>b__7_0() (at Assets/RoomListEntry.cs:31)
UnityEngine.EventSystems.EventSystem:Update() (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/EventSystem.cs:377)
一旦maxPlayers = 4;を1に変更して試してみる。
そうするとエラーが次のように出てくる。
JoinRoom failed. Client is on MasterServer (must be Master Server for matchmaking)but not ready for operations (State: Joining). Wait for callback: OnJoinedLobby or OnConnectedToMaster.
UnityEngine.Debug:LogError(Object)
Photon.Pun.PhotonNetwork:JoinRoom(String, String[]) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1791)
RoomListEntry:<Start>b__7_0() (at Assets/RoomListEntry.cs:31)
UnityEngine.EventSystems.EventSystem:Update() (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/EventSystem.cs:377)
ルームが生成されていないのが問題かと考え、SceneManager.LoadSceneAsync(roomName, LoadSceneMode.Single);の部分を”Sample”シーンへの移行へ変更。
JoinRoom failed. Client is on GameServer (must be Master Server for matchmaking) and ready. Wait for callback: OnJoinedLobby or OnConnectedToMaster.
UnityEngine.Debug:LogError(Object)
Photon.Pun.PhotonNetwork:JoinRoom(String, String[]) (at Assets/Photon/PhotonUnityNetworking/Code/PhotonNetwork.cs:1791)
RoomListEntry:<Start>b__7_0() (at Assets/RoomListEntry.cs:31)
UnityEngine.EventSystems.EventSystem:Update() (at /Users/builduser/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/EventSystem.cs:377)
RoomListEntryでエラーが出ているのに気づき、RoomListEntryのスクリプトの方が問題なのかもしれないと見直す。
// リスト要素がクリックされたら、対応したルーム名のルームに参加する
button.onClick.AddListener(() => PhotonNetwork.JoinRoom(roomName));
この部分がエラーの要因となっている。
ロビーからルームに参加している状態で、かつ、既定の人数が揃ったらそのメンバーで遷移するという風に考えるべきなのかもしれない。
まずは一人の場合で考え、ダブりになっている button.onClick.AddListener(() => PhotonNetwork.JoinRoom(roomName));の部分を//で一旦保留にさせる。
そうするとエラーの表示は一旦消えた。
RoomlistViewの中にあるcontent下のRoomlistentryボタンのonclickにnetworkmanagerのJoinOrCreateRoom()メソッドを読み取らせるようにしたら無事に遷移。
遷移した後にオブジェクトが自動生成されていない点がネック。
Sample scene内でオブジェクトが自動生成されるのは、マッチングが成功した時に呼ばれるコールバックpublic override void OnJoinedRoom()メソッド内で座標を指定して生成する形をとっている。
Sample scene内ではマッチングが成功した時に呼ばれるコールバックは既に呼ばれ終わっているので、自動生成されないのではないかと考えた。
PhotonNetwork.IsMessageQueueRunning = false; true;での操作がうまくはまっていないので工夫する。
処理を止めている間に受信したメッセージは内部のキューにためられ、再開した後に全て受信した順に処理が行われるはずなのでデバッグでも確認してみる。
public override void OnJoinedRoom()の下にDebug.Log(" " + PhotonNetwork.IsMessageQueueRunning);を入れたらルームでは呼ばれていないことがわかった。