【Unity】PUN2 で RPC する際のメソッドの引数について

Unity

はじめに

この記事では PUN2(Photon Unity Networking 2)で RPC する際のメソッドの引数についてメモしておきます。

RPC(Remote Procedure Call)とは直訳すると「遠く離れた手続きの呼び出し」となります。
つまり、一言でいうと他のプレイヤーと「同時」に「同じ」メソッドを実行するということです。
この RPC の基本的な使用方法などに関しては o8que 様の「🔄 同期2 : RPC」が参考になるかと思います。

検証用のプロジェクトについて

この記事での検証に使用した簡易的なプロジェクトについて説明します。
ゲーム画面は Unity のデフォルトの空間に「Taro」と「Hanako」という2つのテキストが表示されるだけという非常にシンプルな内容です。

2人のプレイヤーが1人ずつ同じルームに参加し、画面に各プレイヤーの名前を表示させます。
1人目のプレイヤーの名前は「Taro」で2人目は「Hanako」とします。

検証

では早速検証していきます。

スクリプト

今回の検証で作成したスクリプトは2つあります。
1つは PhotonController.cs で、もう1つは PlayerController.cs です。

PhotonController.cs

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

PlayerController.cs では自身の座標を調整してプレイヤー名をテキストに設定しています。

RPC メソッドの引数を利用した場合

まずは RPC を実行する際にその 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()
    {
        // transform の調整など
        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)
    {
        //受け取ったプレイヤー名をテキストに設定する
        transform.GetChild(0).GetChild(0).GetComponent<Text>().text = name;
    }

    //他のプレイヤーが同じルームに参加したときに呼び出される
    public override void OnPlayerEnteredRoom(Player newPlayer)
    {
        //プレイヤー名を引数に渡して RPC メソッドを呼び出す
        photonView.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All, myName);
    }
}
RPC メソッドの引数を利用しない場合

次は RPC を実行する際にその 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()
    {
        // transform の調整など
        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()
    {
        //メンバー変数に格納されているプレイヤー名をテキストに設定する
        transform.GetChild(0).GetChild(0).GetComponent<Text>().text = myName;
    }

    //他のプレイヤーが同じルームに参加したときに呼び出される
    public override void OnPlayerEnteredRoom(Player newPlayer)
    {
        //プレイヤー名を引数に渡さずに RPC メソッドを呼び出す
        photonView.RPC(nameof(RpcDisplayPlayerName), RpcTarget.All);
    }
}

結果

これらのコードでゲームを実行したときの結果です。

RPC メソッドの引数を利用した場合

RPC メソッドの引数を利用したときは1人目のプレイヤーも2人目のプレイヤーも画面には「Taro」と「Hanako」と表示されています。

1人目「Taro」の画面
2人目「Hanako」の画面

RPC メソッドの引数を利用しなかった場合

ですが、RPC メソッドの引数を利用しなかったときは1人目のプレイヤーは「Taro」とだけ表示されていて、2人目のプレイヤーは「Hanako」とだけ表示されています。

1人目「Taro」の画面
2人目「Hanako」の画面

結論

RPC で同期を行うときは「RPC メソッドの引数を利用するかしないか」で結果が大きく変わってしまうので「RPC で呼び出しているはずなのになぜか上手くいかない…」となってしまったときはその RPC メソッドの引数に注目してみると良いかと思います。

ちなみに PUN2 での RPC の引数に使用可能な型は以下の通りです。

  • 値型(byte、int、float など)
  • 値型の配列(byte[]、int[]、float[] など)
  • その他(Vecter3、Quaternion など)

最後に

参考記事

お問い合わせ

    タイトルとURLをコピーしました