code VR

Unity×VR(23)

スポンサーリンク

//tips

//PUN2ルームの同期設定

カスタムプロパティはルームに設定することもでき、ルームに参加しているプレイヤー全員と、任意の値を同期させたい場合に活用する。

ルームのカスタムプロパティを取得・設定するクラス(GameRoomProperty)を作成。

using Photon.Realtime;
using Hashtable = ExitGames.Client.Photon.Hashtable;

public static class GameRoomProperty
{
private const string KeyDisplayName = "DisplayName"; // 表示用ルーム名のキーの文字列
private const string KeyStartTime = "StartTime"; // ゲーム開始時刻のキーの文字列

private static Hashtable hashtable = new Hashtable();

// ルームの初期設定オブジェクトを作成する
public static RoomOptions CreateRoomOptions(string displayName)
{
return new RoomOptions()
{
// カスタムプロパティの初期設定
CustomRoomProperties = new Hashtable() {
{ KeyDisplayName, displayName }
},
// ロビーからカスタムプロパティを取得できるようにする
CustomRoomPropertiesForLobby = new string[] {
KeyDisplayName
}
};
}

// 表示用ルーム名を取得する
public static string GetDisplayName(this Room room)
{
return (string)room.CustomProperties[KeyDisplayName];
}

// ゲーム開始時刻が設定されているか調べる
public static bool HasStartTime(this Room room)
{
return room.CustomProperties.ContainsKey(KeyStartTime);
}

// ゲーム開始時刻があれば取得する
public static bool TryGetStartTime(this Room room, out int timestamp)
{
if (room.CustomProperties[KeyStartTime] is int value)
{
timestamp = value;
return true;
}
timestamp = 0;
return false;
}

// ゲーム開始時刻を設定する
public static void SetStartTime(this Room room, int timestamp)
{
hashtable[KeyStartTime] = timestamp;

room.SetCustomProperties(hashtable);
hashtable.Clear();
}
}

シーンにテキストを追加して、ゲームの経過時間を表示できるようにしてみる。

GameRoomHUDを作成。

using Photon.Pun;
using TMPro;
using UnityEngine;

[RequireComponent(typeof(TextMeshProUGUI))]
public class GameRoomHUD : MonoBehaviour
{
private TextMeshProUGUI timeLabel;

private void Awake()
{
timeLabel = GetComponent<TextMeshProUGUI>();
}

private void Update()
{
// まだルームに参加していない時は更新しない
if (!PhotonNetwork.InRoom) { return; }
// まだゲーム開始時刻が設定されていない時は更新しない
if (!PhotonNetwork.CurrentRoom.TryGetStartTime(out int timestamp)) { return; }

// ゲーム開始時刻からの経過時間を求めて、テキスト表示する
float elapsedTime = Mathf.Max(unchecked(PhotonNetwork.ServerTimestamp - timestamp) / 1000f);
timeLabel.text = elapsedTime.ToString("f2"); // 小数点以下2桁表示
}
}

これをcanvasの子要素に設定しているtext mesh pro UGUIを含むHUDにアタッチするもテキストに反映されなかった。

SampleSceneスクリプトのマッチングが成功した時に呼ばれるコールバックに下記のスクリプトを追加することで無事動いた。

// 現在のサーバー時刻を、ゲームの開始時刻に設定する
if (PhotonNetwork.IsMasterClient && !PhotonNetwork.CurrentRoom.HasStartTime()) {
PhotonNetwork.CurrentRoom.SetStartTime(PhotonNetwork.ServerTimestamp);
}

Photonがデフォルトでサポートしていないデータ型でも、データ型からバイト列へのシリアライズ処理とバイト列からデータ型へのデシリアライズ処理を実装して登録することで、通信コストを削減する工夫を行うことができる。

例えば、Color型をカスタムタイプとして登録すると、Color型のRGBA値はfloat型なので、そのままバイト列に書き込むためには、合計で16バイト必要となるが、Color32型のRGBA値はbyte型で合計で4バイトで済むため、型変換することによって通信量を削減できる。

オンラインゲームでは様々なタイミングでプレイヤーが途中参加したり途中退出したりする可能性があるので、同じルームに参加しているプレイヤーを適切に管理するための機能を確認する。

MonoBehaviourPunCallbacksを継承しているスクリプト(public class SampleScene : MonoBehaviourPunCallbacksが該当)は、自身が参加しているルームに他プレイヤーが参加・退出した時のコールバックを受け取ることができる。他プレイヤーの情報は、コールバックの引数として渡される。

ルームに参加しているプレイヤーの情報は、PhotonNetworkの配列にアクセスすることで取得できる。

Player[] allPlayers = PhotonNetwork.PlayerList; // プレイヤーの配列(自身を含む)
Player[] otherPlayers = PhotonNetwork.PlayerListOthers; // プレイヤーの配列(自身を含まない)
PhotonView[] photonViews = PhotonNetwork.PhotonViews; // ネットワークオブジェクトの配列

ただ、これらは頻繁にアクセスする際はパフォーマンス上の問題が発生する可能性があるので、ネットワークオブジェクトのリストを管理する独自クラスGamePlayerManagerを作成するのが推奨されている。

新たに空オブジェクトを作成し、そこにスクリプトをアタッチする。

using System.Collections.Generic;
using UnityEngine;

public class GamePlayerManager : MonoBehaviour
{
private List<GamePlayer> playerList = new List<GamePlayer>();

public GamePlayer this[int index] => playerList[index];
public int Count => playerList.Count;

private void OnTransformChildrenChanged()
{
// 子要素が変わったら、ネットワークオブジェクトのリストを更新する
playerList.Clear();
foreach (Transform child in transform)
{
playerList.Add(child.GetComponent<GamePlayer>());
}
}
}

その上で、各GamePlayerが、生成されたらGamePlayerManagerの子要素になるように設定する。GamePlayerスクリプトを一部編集した。

public Player Owner => photonView.Owner;

private void Awake()
{
projectileManager = GameObject.FindWithTag("ProjectileManager").GetComponent<ProjectileManager>();
spriteRenderer = GetComponent<Renderer>();

var gamePlayerManager = GameObject.FindWithTag("GamePlayerManager").GetComponent<GamePlayerManager>();
transform.SetParent(gamePlayerManager.transform);
}

GamePlayerManager側ではOnTransformChildrenChanged()が呼ばれるので、そこでネットワークオブジェクトリストの更新を行う。

ここまでは、同じルームに参加していることを前提に進めていたが、

・ルームの数や種類があらかじめ決まっている場合

この際には、PhotonNetwork.JoinOrCreateRoom()を使用すると便利で、これにより、指定した名前のルームが既に作成されていたら参加し、作成されていなかったら作成してから参加することができる。

PhotonNetwork.JoinOrCreateRoom("Room1", new RoomOptions() { MaxPlayers = 4 }, TypedLobby.Default);

・各プレイヤーが自由にルームを作成したり、作成されたルームに参加したりする場合

などのパターンがあるので、そちらも考慮していく。

//Text mesh proのボヤけ解消

Text mesh pro UGUIは普通のテキストよりボヤけにくいと言われているが初期のLiberationSansフォントの36サイズでscale-1のオブジェクトを作成すると若干ぼやけて見える。

これを解消するためにmaterial presetをdrop shadowに切り替えてみると黒いぼやけがとれ、くっきりと指定したvertex colorが現れる。

 

人気の記事

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.