「RPC」と引数
「RPC」とは
「RPC(Remote Procedure Call)」とは
直訳すると「遠く離れた手続きの呼び出し」であり、
要するに、
「他のプレイヤーと『同時』に『同じ』メソッドを実行する」
という事である。
基本的な使用方法などに関しては
サンプルゲーム概要
2人のプレイヤーがオンラインでゲームに参加し、
画面に各プレイヤーの名前を表示する。
1人目は「Taro」で、2人目は「Hanako」。

コード
PhotonController.cs
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
public class PhotonController : MonoBehaviourPunCallbacks
{
//マスターサーバーに接続しているかどうか
private bool isConnecting;
private void Awake()
{
//マスタークライアントと同じシーンを読み込む
PhotonNetwork.AutomaticallySyncScene = true;
}
private void Start()
{
//マスターサーバーに接続したなら、
if (PhotonNetwork.IsConnected)
{
//ランダムなルームに参加する
PhotonNetwork.JoinRandomRoom();
}
//マスターサーバーに接続していないなら
else
{
//マスターサーバーに接続し、結果を取得する
isConnecting = PhotonNetwork.ConnectUsingSettings();
}
}
//マスターサーバーに接続した際に呼び出される
public override void OnConnectedToMaster()
{
//マスターサーバーに接続しているなら
if (isConnecting)
{
//「room」に参加する
PhotonNetwork.JoinOrCreateRoom
("room", new RoomOptions(), TypedLobby.Default);
//マスターサーバーに接続していない状態に切り替える
//(ゲームサーバーに接続するため)
isConnecting = false;
}
}
//ゲームサーバーに接続した際に呼び出される
public override void OnJoinedRoom()
{
//ネットワークオブジェクトを生成し、
//初期設定を行う
PhotonNetwork
.Instantiate("Player", Vector3.zero, Quaternion.identity)
.GetComponent<PlayerController>()
.SetUp();
}
}
PlayerController.cs
「RPC」メソッドの引数を利用した場合
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(PhotonView), typeof(PhotonTransformView))]
public class PlayerController : MonoBehaviourPunCallbacks
{
//自分の名前
private string myName;
//自身の生成直後に呼び出される
public void SetUp()
{
//適切なy座標を取得する
float posY =
PhotonNetwork.LocalPlayer.IsMasterClient ?
3f : -1f;
//自身の座標を設定する
transform.position = new(0f, posY, 0f);
//メインカメラを自分の所有物にする
Camera.main.transform.SetParent(transform);
//自分の名前を取得する
myName =
PhotonNetwork.LocalPlayer.IsMasterClient ?
"Taro" : "Hanako";
//RPCメソッドを呼び出す
photonView
.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All, myName);
}
//プレイヤーの名前を表示する
[PunRPC]
private void RpcDisplayPlayerName(string name)
{
//Textを取得し、設定する
transform
.GetChild(0)
.GetChild(0)
.GetComponent<Text>().text = name;
}
//他のプレイヤーが同じルームに参加した際に呼び出される
public override void OnPlayerEnteredRoom(Player newPlayer)
{
//RPCメソッドを呼び出す
photonView
.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All, myName);
}
}
「RPC」メソッドの引数を利用しない場合
using Photon.Pun;
using Photon.Realtime;
using UnityEngine;
using UnityEngine.UI;
[RequireComponent(typeof(PhotonView), typeof(PhotonTransformView))]
public class PlayerController : MonoBehaviourPunCallbacks
{
//自分の名前
private string myName;
//自身の生成直後に呼び出される
public void SetUp()
{
//適切なy座標を取得する
float posY =
PhotonNetwork.LocalPlayer.IsMasterClient ?
3f : -1f;
//自身の座標を設定する
transform.position = new(0f, posY, 0f);
//メインカメラを自分の所有物にする
Camera.main.transform.SetParent(transform);
//自分の名前を取得する
myName =
PhotonNetwork.LocalPlayer.IsMasterClient ?
"Taro" : "Hanako";
//RPCメソッドを呼び出す
photonView
.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All);
}
//プレイヤーの名前を表示する
[PunRPC]
private void RpcDisplayPlayerName()
{
//Textを取得し、設定する
transform
.GetChild(0)
.GetChild(0)
.GetComponent<Text>().text = myName;
}
//他のプレイヤーが同じルームに参加した際に呼び出される
public override void OnPlayerEnteredRoom(Player newPlayer)
{
//RPCメソッドを呼び出す
photonView
.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All);
}
}
結果
「RPC」メソッドの引数を利用した場合
「Taro」視点(1人目)

「Hanako」視点(2人目)

「RPC」メソッドの引数を利用しない場合
「Taro」視点(1人目)

「Hanako」視点(2人目)

説明
スクリプト解説
PhotonController.cs
- マスターサーバーへの接続
- ゲームサーバーへの接続
- 「Player」(ネットワークオブジェクト)の生成
- 生成した「Player」(ネットワークオブジェクト)の初期設定
を行っている。
PlayerController.cs
- 自身の座標の設定
- カメラの親の設定
- 自身の名前の取得(「マスタークライアントがどうか」の条件分岐によって、1人目は「Taro」、2人目は「Hanako」になる)
- 「自身が生成されたタイミング」と「他のプレイヤーが参加したタイミング」で、プレイヤー名を表示
を行っており、
「『RPC』メソッドで引数を利用するか、利用しないか」
という違いで2つのスクリプトを作成してある。
結果の違い
前述したように「PlayerController.cs」の2つのスクリプトの違いは
「『RPC』メソッドで引数を利用するか、利用しないか」
という事だが、
結果は大きく異なる。
引数を利用した方は、2人とも正常に各プレイヤー名が表示されているが、
引数を利用していない方は、それぞれ自分の名前しか表示されていない。
原因
自分は「Photon」の開発チームのメンバーではないため
正確な原因・理由は分からないが、
「RPC」によって実行されるメソッド内の変数は
引数を利用して渡してあげない限りは「空」になるのではないだろうか。
今回の場合の変数は「myName」変数で
「string」型は「Null許容型」ではないため、「null」ではなく
「string.Empty」が格納されていたのだと思われる。
結論
「RPC」を用いて同期を行う際は
「引数を利用するかしないか」で
大きく結果が変わるため、
「『RPC』で呼び出しているはずなのに、なぜかうまくいかない…」
と悩んでしまったら、
引数を利用することも考えよう。
ちなみに「RPC」の引数に使える型は
- 値型(byte・int・float等)
- 値型の配列(byte[]・int[]・float[]等)
- 文字列(string・string[])
- その他(Vecter3・Quaternion等)
である。
コメント