code VR

Unity×VR(24)

スポンサーリンク

//tips

//PUN2 ルーム作成パターン

プレイヤー同士のマッチング方法は、ルームの数や種類が固定されたものや自由にルームを作成したり、作成されたルームに参加したりするものがある。

Photonのロビー機能を使い、ルーム選択型のマッチングを考えていく。

マスターサーバーへの接続が成功した後にPhotonNetwork.JoinLobby()でロビーに参加すると、MonoBehaviourPunCallbacksを継承しているスクリプトは、ルームリストの更新をコールバックで受け取ることができるようになる。

コールバックの引数には、変更(追加・更新・削除)があったルームの情報が渡されるので、それを元にUIへ反映させる。

// マスターサーバーへの接続が成功したら、ロビーに参加する
public override void OnConnectedToMaster() {
PhotonNetwork.JoinLobby();
}

ルーム選択リスト(RoomListView)とそのリスト要素(RoomListEntry)を実装する。

ルーム選択リストはスクロールビューで作成する。canvas下に作成したスクロールビューに下記のスクリプトをアタッチ。

using System.Collections.Generic;
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(ScrollRect))]
public class RoomListView : MonoBehaviourPunCallbacks
{
[SerializeField]
private RoomListEntry roomListEntryPrefab = default; // RoomListEntryのPrefabの参照

private ScrollRect scrollRect;
private Dictionary<string, RoomListEntry> activeEntries = new Dictionary<string, RoomListEntry>();
private Stack<RoomListEntry> inactiveEntries = new Stack<RoomListEntry>();

private void Awake()
{
scrollRect = GetComponent<ScrollRect>();
}

// ルームリストが更新された時に呼ばれるコールバック
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
foreach (var info in roomList)
{
RoomListEntry entry;
if (activeEntries.TryGetValue(info.Name, out entry))
{
if (!info.RemovedFromList)
{
// リスト要素を更新する
entry.Activate(info);
}
else
{
// リスト要素を削除する
activeEntries.Remove(info.Name);
entry.Deactivate();
inactiveEntries.Push(entry);
}
}
else if (!info.RemovedFromList)
{
// リスト要素を追加する
entry = (inactiveEntries.Count > 0)
? inactiveEntries.Pop().SetAsLastSibling()
: Instantiate(roomListEntryPrefab, scrollRect.content);
entry.Activate(info);
activeEntries.Add(info.Name, entry);
}
}
}
}

そして、別途ボタンを作成し、その下に3つのtext mesh pro uguiを追加する。

ボタンには下記のスクリプトをアタッチする。

using Photon.Pun;
using Photon.Realtime;
using TMPro;
using UnityEngine;
using UnityEngine.UI;

[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(Button))]
public class RoomListEntry : MonoBehaviour
{
[SerializeField]
private TextMeshProUGUI nameLabel = default;
[SerializeField]
private TextMeshProUGUI messageLabel = default;
[SerializeField]
private TextMeshProUGUI playerCounter = default;

private RectTransform rectTransform;
private Button button;
private string roomName;

private void Awake()
{
rectTransform = GetComponent<RectTransform>();
button = GetComponent<Button>();
}

private void Start()
{
// リスト要素がクリックされたら、対応したルーム名のルームに参加する
button.onClick.AddListener(() => PhotonNetwork.JoinRoom(roomName));
}

public void Activate(RoomInfo info)
{
roomName = info.Name;

nameLabel.text = (string)info.CustomProperties["DisplayName"];
messageLabel.text = (string)info.CustomProperties["Message"];
playerCounter.SetText("{0}/{1}", info.PlayerCount, info.MaxPlayers);
// ルームの参加人数が満員でない時だけ、クリックできるようにする
button.interactable = (info.PlayerCount < info.MaxPlayers);

gameObject.SetActive(true);
}

public void Deactivate()
{
gameObject.SetActive(false);
}

public RoomListEntry SetAsLastSibling()
{
rectTransform.SetAsLastSibling();
return this;
}
}

クリックされたらPhotonNetwork.JoinRoom()でルーム選択リストから渡されたルーム名のルームへの参加を試みる処理を行なっている。

作成したLIst要素にLayout Elementコンポーネントを追加し、繰り返し表示されるオブジェクトの最低・最大幅などを設定している。

作成したRoomListEntryはprefab化してヒエラルキーから消去。

繰り返し表示したいオブジェクトをContentの子要素に追加することで一覧表示していく。

Contentの子要素に入れたオブジェクトが自動整列されるよう、Contentにコンポーネントを追加する。追加された子要素を縦方向に整列していくVertical Layout Group コンポーネント、追加された子要素の数に応じて、Contentのサイズを自動調整するContent Size Fitter コンポーネントを加える。

Vertical Layout Groupのpaddingで表示余白を微調整する。

このようにロビーのマッチング場所を作成することができる。

現在はリストの内容をクリックしても部屋に入れないので、リスト項目をクリックしたらルームに移行できるようにしたいので、まずはルームの作成方法を見ていく。

今まではひとつのルームの中の活動しか見てこなかったので、並列して複数のルームが生成されている状態を考えていく。

まずはボタンを押すとルームを作成する仕組みを考える。

下記を参考にし、作成。

【Unity】3. ルームの作成と入室【PUN2】

using ExitGames.Client.Photon;
using Photon.Pun;
using Photon.Realtime;
using System.Collections.Generic;
using UnityEngine;

public class NetworkManager : MonoBehaviourPunCallbacks
{
/////////////////////////////////////////////////////////////////////////////////////
// Field ////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

[Header("DefaultRoomSettings")]

// 最大人数
[SerializeField] private int maxPlayers = 4;

// 公開・非公開
[SerializeField] private bool isVisible = true;

// 入室の可否
[SerializeField] private bool isOpen = true;

// 部屋名
[SerializeField] private string roomName = "Naki's Room";

// ステージ
[SerializeField] private string stageName = "Stage1";

// 難易度
[SerializeField] private string stageDifficulty = "Easy";

/////////////////////////////////////////////////////////////////////////////////////
// Awake & Start ////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

// Awake
private void Awake()
{
// シーンの自動同期: 無効
PhotonNetwork.AutomaticallySyncScene = false;
}

// Start is called before the first frame update
private void Start()
{
// Photonに接続
Connect("1.0");
}

/////////////////////////////////////////////////////////////////////////////////////
// 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;
}
}

/////////////////////////////////////////////////////////////////////////////////////
// Join Lobby ///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

// ロビーに入る
private void JoinLobby()
{
if (PhotonNetwork.IsConnected)
{
PhotonNetwork.JoinLobby();
}
}

/////////////////////////////////////////////////////////////////////////////////////
// Join Room ////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

// 1. 部屋を作成して入室する
public void CreateAndJoinRoom()
{
// ルームオプションの基本設定
RoomOptions roomOptions = new RoomOptions
{
// 部屋の最大人数
MaxPlayers = (byte)maxPlayers,

// 公開
IsVisible = isVisible,

// 入室可
IsOpen = isOpen
};

// ルームオプションにカスタムプロパティを設定
ExitGames.Client.Photon.Hashtable customRoomProperties = new ExitGames.Client.Photon.Hashtable
{
{ "Stage", stageName },
{ "Difficulty", stageDifficulty }
};
roomOptions.CustomRoomProperties = customRoomProperties;

// ロビーに公開するカスタムプロパティを指定
roomOptions.CustomRoomPropertiesForLobby = new string[] { "Stage", "Difficulty" };

// 部屋を作成して入室する
if (PhotonNetwork.InLobby)
{
PhotonNetwork.CreateRoom(roomName, roomOptions);
}
}

// 2. 部屋に入室する (存在しなければ作成して入室する)
public void JoinOrCreateRoom()
{
// ルームオプションの基本設定
RoomOptions roomOptions = new RoomOptions
{
// 部屋の最大人数
MaxPlayers = (byte)maxPlayers,

// 公開
IsVisible = isVisible,

// 入室可
IsOpen = isOpen
};

// ルームオプションにカスタムプロパティを設定
ExitGames.Client.Photon.Hashtable customRoomProperties = new ExitGames.Client.Photon.Hashtable
{
{ "Stage", stageName },
{ "Difficulty", stageDifficulty }
};
roomOptions.CustomRoomProperties = customRoomProperties;

// ロビーに公開するカスタムプロパティを指定
roomOptions.CustomRoomPropertiesForLobby = new string[] { "Stage", "Difficulty" };

// 入室 (存在しなければ部屋を作成して入室する)
if (PhotonNetwork.InLobby)
{
PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
}
}

// 3. 特定の部屋に入室する
public void JoinRoom(string targetRoomName)
{
if (PhotonNetwork.InLobby)
{
PhotonNetwork.JoinRoom(targetRoomName);
}
}

// 4. ランダムな部屋に入室する
public void JoinRandomRoom()
{
if (PhotonNetwork.InLobby)
{
PhotonNetwork.JoinRandomRoom();
}
}

/////////////////////////////////////////////////////////////////////////////////////
// Leave Room ///////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

// 部屋から退室する
public void LeaveRoom()
{
if (PhotonNetwork.InRoom)
{
// 退室
PhotonNetwork.LeaveRoom();
}
}

/////////////////////////////////////////////////////////////////////////////////////
// Pun Callbacks ////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////

// Photonに接続した時
public override void OnConnected()
{
Debug.Log("OnConnected");

// ニックネームを付ける
SetMyNickName("Naki");
}

// Photonから切断された時
public override void OnDisconnected(DisconnectCause cause)
{
Debug.Log("OnDisconnected");
}

// マスターサーバーに接続した時
public override void OnConnectedToMaster()
{
Debug.Log("OnConnectedToMaster");

// ロビーに入る
JoinLobby();
}

// ロビーに入った時
public override void OnJoinedLobby()
{
Debug.Log("OnJoinedLobby");
}

// ロビーから出た時
public override void OnLeftLobby()
{
Debug.Log("OnLeftLobby");
}

// 部屋を作成した時
public override void OnCreatedRoom()
{
Debug.Log("OnCreatedRoom");
}

// 部屋の作成に失敗した時
public override void OnCreateRoomFailed(short returnCode, string message)
{
Debug.Log("OnCreateRoomFailed");
}

// 部屋に入室した時
public override void OnJoinedRoom()
{
Debug.Log("OnJoinedRoom");

// 部屋の情報を表示
if (PhotonNetwork.InRoom)
{
Debug.Log("RoomName: " + PhotonNetwork.CurrentRoom.Name);
Debug.Log("HostName: " + PhotonNetwork.MasterClient.NickName);
Debug.Log("Stage: " + PhotonNetwork.CurrentRoom.CustomProperties["Stage"] as string);
Debug.Log("Difficulty: " + PhotonNetwork.CurrentRoom.CustomProperties["Difficulty"] as string);
Debug.Log("Slots: " + PhotonNetwork.CurrentRoom.PlayerCount + " / " + PhotonNetwork.CurrentRoom.MaxPlayers);
}
}

// 特定の部屋への入室に失敗した時
public override void OnJoinRoomFailed(short returnCode, string message)
{
Debug.Log("OnJoinRoomFailed");
}

// ランダムな部屋への入室に失敗した時
public override void OnJoinRandomFailed(short returnCode, string message)
{
Debug.Log("OnJoinRandomFailed");
}

// 部屋から退室した時
public override void OnLeftRoom()
{
Debug.Log("OnLeftRoom");
}

// 他のプレイヤーが入室してきた時
public override void OnPlayerEnteredRoom(Player newPlayer)
{
Debug.Log("OnPlayerEnteredRoom");
}

// 他のプレイヤーが退室した時
public override void OnPlayerLeftRoom(Player otherPlayer)
{
Debug.Log("OnPlayerLeftRoom");
}

// マスタークライアントが変わった時
public override void OnMasterClientSwitched(Player newMasterClient)
{
Debug.Log("OnMasterClientSwitched");
}

// ロビーに更新があった時
public override void OnLobbyStatisticsUpdate(List<TypedLobbyInfo> lobbyStatistics)
{
Debug.Log("OnLobbyStatisticsUpdate");
}

// ルームリストに更新があった時
public override void OnRoomListUpdate(List<RoomInfo> roomList)
{
Debug.Log("OnRoomListUpdate");
}

// ルームプロパティが更新された時
public override void OnRoomPropertiesUpdate(ExitGames.Client.Photon.Hashtable propertiesThatChanged)
{
Debug.Log("OnRoomPropertiesUpdate");
}

// プレイヤープロパティが更新された時
public override void OnPlayerPropertiesUpdate(Player target, ExitGames.Client.Photon.Hashtable changedProps)
{
Debug.Log("OnPlayerPropertiesUpdate");
}

// フレンドリストに更新があった時
public override void OnFriendListUpdate(List<FriendInfo> friendList)
{
Debug.Log("OnFriendListUpdate");
}

// 地域リストを受け取った時
public override void OnRegionListReceived(RegionHandler regionHandler)
{
Debug.Log("OnRegionListReceived");
}

// WebRpcのレスポンスがあった時
public override void OnWebRpcResponse(OperationResponse response)
{
Debug.Log("OnWebRpcResponse");
}

// カスタム認証のレスポンスがあった時
public override void OnCustomAuthenticationResponse(Dictionary<string, object> data)
{
Debug.Log("OnCustomAuthenticationResponse");
}

// カスタム認証が失敗した時
public override void OnCustomAuthenticationFailed(string debugMessage)
{
Debug.Log("OnCustomAuthenticationFailed");
}
}

この仕組みをスクロールビューにも組み込んでいく。

まずはクリックしたルームに入れるようにし、その後、スクロールビューにAddボタンを追加し、押したら新規ルームが作成できるようにする。

現在roomlistentryクラスでroomへの参加は下記コードで表されているが、そのルーム名のルームがないのが問題。

private void Start()
{
// リスト要素がクリックされたら、対応したルーム名のルームに参加する
button.onClick.AddListener(() => PhotonNetwork.JoinRoom(roomName));
}

ロビーにRoomの名前が記載されている時点でルーム作成されている必要があるので、roomlistviewの初期段階でひとつサンプルroomを作成するようにする。

ここでロビーからルームへの移行の仕方がわからず検証中。コンソールからはルームに接続できていることは確認できているので、どう状態を移行させるかが問題。

人気の記事

1

皆さん、ついに、エアラインでも、サブスクリプションが始まったのはご存じですか? まだ実験段階ですが、ANAが、定額全国住み放題サービスを提供する「ADDress」と組んで、国内線を4回まで定額利用可能 ...

2

無料でネットショップを開けるアプリとして多くの人に驚きを与えたBASE株式会社が、2019年10月25日東証マザーズに上場しました。2020年2月時点で90万店を超えるショップを抱えるまでに成長してい ...

3

2011年にサービスを開始してから圧倒的な成長率を誇るインテリア通販サイト 【FLYMEe/フライミー】を皆さんご存じでしょうか。 「自分のイメージするインテリア、本当に欲しいインテリアがどこにあるの ...

4

ついに、noteの月間アクティブユーザー数が4400万人(2020年3月時点)に到達しました。 そもそも、「note」とは、クリエイターが、文章やマンガ、写真、音声を投稿することができ、ユーザーはその ...

5

ボードゲームカフェが1日2回転で儲かるという記事をみつけたので興味を持ち、調べてみました。 まずは、需要がどれくらいあるのか、市場のようすからみていきましょう。 世界最大のボードゲーム市場はドイツで、 ...

-code, VR
-,

Copyright© BUSINESS HUNTER , 2023 All Rights Reserved Powered by AFFINGER5.