Photon Network (クラシック) 初心者ガイド

Photon Network は、開発者がリアルタイム マルチプレイヤー ゲームを作成できるようにする Unity 用のサービスです。

強力で使いやすい API を提供するため、初心者の開発者にも最適です。

この投稿では、必要なファイルのダウンロード、Photon AppID のセットアップ、簡単なマルチプレイヤーのサンプルのプログラミングまでを実行します。

パート 1: Photon Network のセットアップ

最初のステップは、Asset Store から Photon Network パッケージをダウンロードすることです。これには、マルチプレイヤー統合に必要なすべてのスクリプトとファイルが含まれています。

  • Unity プロジェクト を開き、Asset Store に移動します: (ウィンドウ -> 一般 -> AssetStore) または Ctrl+9 を押します。
  • Photon Unity Networking Classic - Free」を検索し、最初の結果をクリックするか、ここをクリックしてください
  • ダウンロードが完了したら、Photon パッケージをインポートします

  • パッケージをインポートした後、Photon App ID を作成する必要があります。これは Web サイト (https://www.photonengine.com/) で行われます。
  • 新しいアカウントを作成します (または既存のアカウントにログインします)
  • プロフィール アイコンをクリックして [アプリケーション] ページに移動し、"Your Applications" をクリックするか、次のリンクをクリックします: https://dashboard.photonengine.com/en-US/PublicCloud
  • 「アプリケーション」ページで、 をクリックします。 "Create new app"

  • 作成ページで、Photon Type に "Photon Realtime" を選択し、Name に任意の名前を入力して、 "Create"

ご覧のとおり、アプリケーションはデフォルトで無料プランに設定されています。料金プラン の詳細については、こちらをご覧ください。

  • アプリケーションが作成されたら、アプリ名の下にあるアプリ ID をコピーします。

  • Unity プロジェクトに戻り、[ウィンドウ] -> [Photon Unity ネットワーク] -> [PUN ウィザード] に移動します。
  • PUN ウィザードで "Setup Project" をクリックし、アプリ ID を貼り付けて、 "Setup Project"
  • Photon Networkの準備が整いました

パート 2: マルチプレイヤー ゲームの作成

それでは、実際にマルチプレイヤー ゲームを作成する部分に移りましょう。

Photon でのマルチプレイヤーの処理方法は次のとおりです。

  • まず、ロビーとも呼ばれる Photon リージョン (例: 米国東部、ヨーロッパ、アジアなど) に接続します。
  • ロビーに入ると、その地域で作成されたすべてのルームをリクエストし、いずれかのルームに参加するか、独自のルームを作成できます。
  • ルームに参加した後、ルームに接続しているプレーヤーのリストをリクエストし、プレーヤー インスタンスをインスタンス化します。その後、PhotonView を通じてローカル インスタンスと同期されます。
  • 誰かがルームを離れると、そのインスタンスは破壊され、プレイヤー リストから削除されます。

1. ロビーのセットアップ

まず、ロビー ロジック (既存のルームの参照、新しいルームの作成など) を含む MainMenu を作成します。

  • 新しいシーンを作成して呼び出します "MainMenu"
  • 新しい C# スクリプトを作成し、GameLobby という名前を付けます。
  • MainMenu シーンで新しい GameObject を作成します。"_GameLobby" という名前を付け、GameLobby スクリプトをアタッチします。

次に、GameLobby スクリプトを開きます。

まず、必要な変数をすべて作成しましょう。

    //Our player name
    string playerName = "Player 1";
    //This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).
    string gameVersion = "0.9";
    //The list of created rooms
    RoomInfo[] createdRooms = new RoomInfo[0];
    //Use this name when creating a Room
    string roomName = "Room 1";
    Vector2 roomListScroll = Vector2.zero;
    bool joiningRoom = false;

次に行う必要があるのは、ロビーの自動参加とロビー統計を有効にすることです。これにより、ルームリストを受信できるようになります。これは void Start() で行われます。

また、AutomaticSyncScene を有効にすると、ルームに参加するとシーンが自動的に同期されます。

最後に、PhotonNetwork.ConnectUsingSettings を呼び出して接続します。

    // Use this for initialization
    void Start()
    {
        //Automatically join Lobby after we connect to Photon Region
        PhotonNetwork.PhotonServerSettings.JoinLobby = true;
        //Enable Lobby Stats to receive the list of Created rooms
        PhotonNetwork.PhotonServerSettings.EnableLobbyStatistics = true;
        //This makes sure we can use PhotonNetwork.LoadLevel() on the master client and all clients in the same room sync their level automatically
        PhotonNetwork.automaticallySyncScene = true;

        if (!PhotonNetwork.connected)
        {
            // Connect to the photon master-server. We use the settings saved in PhotonServerSettings (a .asset file in this project)
            PhotonNetwork.ConnectUsingSettings(gameVersion);
        }
    }

Photon Cloudへの接続が成功したかどうかを知るには、OnReceivedRoomListUpdate()OnFailedToConnectToPhoton(objectparameters)の2つのコールバックを実装する必要があります。

    void OnFailedToConnectToPhoton(object parameters)
    {
        Debug.Log("OnFailedToConnectToPhoton. StatusCode: " + parameters + " ServerAddress: " + PhotonNetwork.ServerAddress);
        //Try to connect again
        PhotonNetwork.ConnectUsingSettings(gameVersion);
    }

    void OnReceivedRoomListUpdate()
    {
        Debug.Log("We have received the Room list");
        //After this callback, PhotonNetwork.GetRoomList() becomes available
        createdRooms = PhotonNetwork.GetRoomList();
    }

次は UI 部分で、ルームの参照とルームの作成が行われます。

フォトンネットワークロビー

最後に、別の 4 つのコールバックを実装します: OnPhotonCreateRoomFailed()OnPhotonJoinRoomFailed(object[] Cause)OnCreatedRoom()、および OnJoinedRoom()

これらのコールバックは、ルームに参加/作成したかどうか、または接続中に問題が発生したかどうかを判断するために使用されます。

    void OnPhotonCreateRoomFailed()
    {
        Debug.Log("OnPhotonCreateRoomFailed got called. This can happen if the room exists (even if not visible). Try another room name.");
        joiningRoom = false;
    }

    void OnPhotonJoinRoomFailed(object[] cause)
    {
        Debug.Log("OnPhotonJoinRoomFailed got called. This can happen if the room is not existing or full or closed.");
        joiningRoom = false;
    }

    void OnCreatedRoom()
    {
        Debug.Log("OnCreatedRoom");
        //Set our player name
        PhotonNetwork.playerName = playerName;
        //Load the Scene called GameLevel (Make sure it's added to build settings)
        PhotonNetwork.LoadLevel("GameLevel");
    }

    void OnJoinedRoom()
    {
        Debug.Log("OnJoinedRoom");
    }

そして、これが最後の GameLobby.cs スクリプトです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameLobby : MonoBehaviour
{
    //Our player name
    string playerName = "Player 1";
    //This client's version number. Users are separated from each other by gameversion (which allows you to make breaking changes).
    string gameVersion = "0.9";
    //The list of created rooms
    RoomInfo[] createdRooms = new RoomInfo[0];
    //Use this name when creating a Room
    string roomName = "Room 1";
    Vector2 roomListScroll = Vector2.zero;
    bool joiningRoom = false;

    // Use this for initialization
    void Start()
    {
        //Automatically join Lobby after we connect to Photon Region
        PhotonNetwork.PhotonServerSettings.JoinLobby = true;
        //Enable Lobby Stats to receive the list of Created rooms
        PhotonNetwork.PhotonServerSettings.EnableLobbyStatistics = true;
        //This makes sure we can use PhotonNetwork.LoadLevel() on the master client and all clients in the same room sync their level automatically
        PhotonNetwork.automaticallySyncScene = true;

        if (!PhotonNetwork.connected)
        {
            // Connect to the photon master-server. We use the settings saved in PhotonServerSettings (a .asset file in this project)
            PhotonNetwork.ConnectUsingSettings(gameVersion);
        }
    }

    void OnFailedToConnectToPhoton(object parameters)
    {
        Debug.Log("OnFailedToConnectToPhoton. StatusCode: " + parameters + " ServerAddress: " + PhotonNetwork.ServerAddress);
        //Try to connect again
        PhotonNetwork.ConnectUsingSettings(gameVersion);
    }

    void OnReceivedRoomListUpdate()
    {
        Debug.Log("We have received the Room list");
        //After this callback, PhotonNetwork.GetRoomList() becomes available
        createdRooms = PhotonNetwork.GetRoomList();
    }

    void OnGUI()
    {
        GUI.Window(0, new Rect(Screen.width/2 - 450, Screen.height/2 - 200, 900, 400), LobbyWindow, "Lobby");
    }

    void LobbyWindow(int index)
    {
        //Connection Status and Room creation Button
        GUILayout.BeginHorizontal();

            GUILayout.Label("Status: " + PhotonNetwork.connectionStateDetailed);

            if(joiningRoom || !PhotonNetwork.connected)
            {
                GUI.enabled = false;
            }

            GUILayout.FlexibleSpace();

            //Room name text field
            roomName = GUILayout.TextField(roomName, GUILayout.Width(250));

            if (GUILayout.Button("Create Room", GUILayout.Width(125)))
            {
                if (roomName != "")
                {
                    joiningRoom = true;

                    RoomOptions roomOptions = new RoomOptions();
                    roomOptions.IsOpen = true;
                    roomOptions.IsVisible = true;
                    roomOptions.MaxPlayers = (byte)10; //Set any number

                    PhotonNetwork.JoinOrCreateRoom(roomName, roomOptions, TypedLobby.Default);
                }
            }

        GUILayout.EndHorizontal();

        //Scroll through available rooms
        roomListScroll = GUILayout.BeginScrollView(roomListScroll, true, true);

            if(createdRooms.Length == 0)
            {
                GUILayout.Label("No Rooms were created yet...");
            }
            else
            {
                for(int i = 0; i < createdRooms.Length; i++)
                {
                    GUILayout.BeginHorizontal("box");
                    GUILayout.Label(createdRooms[i].Name, GUILayout.Width(400));
                    GUILayout.Label(createdRooms[i].PlayerCount + "/" + createdRooms[i].MaxPlayers);

                    GUILayout.FlexibleSpace();
                
                    if (GUILayout.Button("Join Room"))
                    {
                        joiningRoom = true;

                        //Set our Player name
                        PhotonNetwork.playerName = playerName;

                        //Join the Room
                        PhotonNetwork.JoinRoom(createdRooms[i].Name);
                    }
                    GUILayout.EndHorizontal();
                }
            }

        GUILayout.EndScrollView();

        //Set player name and Refresh Room button
        GUILayout.BeginHorizontal();

            GUILayout.Label("Player Name: ", GUILayout.Width(85));
            //Player name text field
            playerName = GUILayout.TextField(playerName, GUILayout.Width(250));

            GUILayout.FlexibleSpace();

            GUI.enabled = PhotonNetwork.connectionState != ConnectionState.Connecting && !joiningRoom;
            if (GUILayout.Button("Refresh", GUILayout.Width(100)))
            {
                if (PhotonNetwork.connected)
                {
                    //We are already connected, simply update the Room list
                    createdRooms = PhotonNetwork.GetRoomList();
                }
                else
                {
                    //We are not connected, estabilish a new connection
                    PhotonNetwork.ConnectUsingSettings(gameVersion);
                }
            }

        GUILayout.EndHorizontal();

        if (joiningRoom)
        {
            GUI.enabled = true;
            GUI.Label(new Rect(900/2 - 50, 400/2 - 10, 100, 20), "Connecting...");
        }
    }

    void OnPhotonCreateRoomFailed()
    {
        Debug.Log("OnPhotonCreateRoomFailed got called. This can happen if the room exists (even if not visible). Try another room name.");
        joiningRoom = false;
    }

    void OnPhotonJoinRoomFailed(object[] cause)
    {
        Debug.Log("OnPhotonJoinRoomFailed got called. This can happen if the room is not existing or full or closed.");
        joiningRoom = false;
    }

    void OnCreatedRoom()
    {
        Debug.Log("OnCreatedRoom");
        //Set our player name
        PhotonNetwork.playerName = playerName;
        //Load the Scene called GameLevel (Make sure it's added to build settings)
        PhotonNetwork.LoadLevel("GameLevel");
    }

    void OnJoinedRoom()
    {
        Debug.Log("OnJoinedRoom");
    }
}

2. Player プレハブの作成

マルチプレイヤー ゲームでは、Player インスタンスにはローカルとリモートの 2 つの側面があります。

ローカル インスタンスはローカルで (弊社によって) 制御されます。

一方、リモート インスタンスは、他のプレイヤーが行っていることをローカルに表現したものです。私たちの入力の影響を受けてはいけません。

インスタンスがローカルかリモートかを判断するには、PhotonView コンポーネントを使用します。

PhotonView は、位置や回転など、同期する必要がある値を送受信するメッセンジャーとして機能します。

それでは、プレーヤー インスタンスを作成することから始めましょう (プレーヤー インスタンスをすでに準備している場合は、この手順をスキップできます)。

私の場合、Player インスタンスは、W キーと S キーで移動し、A キーと D キーで回転する単純な Cube になります。

Photon ネットワーク プレーヤー インスタンス

簡単なコントローラー スクリプトは次のとおりです。

PlayerController.cs

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    // Update is called once per frame
    void Update()
    {
        //Move Front/Back
        if (Input.GetKey(KeyCode.W))
        {
            transform.Translate(transform.forward * Time.deltaTime * 2.45f, Space.World);
        }
        else if (Input.GetKey(KeyCode.S))
        {
            transform.Translate(-transform.forward * Time.deltaTime * 2.45f, Space.World);
        }

        //Rotate Left/Right
        if (Input.GetKey(KeyCode.A))
        {
            transform.Rotate(new Vector3(0, -14, 0) * Time.deltaTime * 4.5f, Space.Self);
        }
        else if (Input.GetKey(KeyCode.D))
        {
            transform.Rotate(new Vector3(0, 14, 0) * Time.deltaTime * 4.5f, Space.Self);
        }
    }
}

次のステップは、PhotonView コンポーネントを追加することです。

  • PhotonView コンポーネントをプレーヤー インスタンスに追加します
  • 新しい C# スクリプトを作成し、PlayerNetworkSync という名前を付けて開きます (このスクリプトは PhotonView を介した通信に使用されます)

最初に行う必要があるのは、MonoBehaviour を Photon.MonoBehaviour に置き換えることです。このステップは、GetComponent<PhotonView>() を使用する代わりに、キャッシュされた photonView 変数を使用できるようにするために必要です。

public class PlayerNetworkSync : Photon.MonoBehaviour

その後、必要な変数をすべて作成します。

    //List of the scripts that should only be active for the local player (ex. PlayerController, MouseLook etc.)
    public MonoBehaviour[] localScripts;
    //List of the GameObjects that should only be active for the local player (ex. Camera, AudioListener etc.)
    public GameObject[] localObjects;
    //Values that will be synced over network
    Vector3 latestPos;
    Quaternion latestRot;

次に、 void Start() で、photonView.isMine を使用してプレーヤーがローカルかリモートかを確認します。

    // Use this for initialization
    void Start()
    {
        if (photonView.isMine)
        {
            //Player is local
        }
        else
        {
            //Player is Remote
            for(int i = 0; i < localScripts.Length; i++)
            {
                localScripts[i].enabled = false;
            }
            for (int i = 0; i < localObjects.Length; i++)
            {
                localObjects[i].SetActive(false);
            }
        }
    }

実際の同期は、PhotonView のコールバック: OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info): を通じて行われます。

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.isWriting)
        {
            //We own this player: send the others our data
            stream.SendNext(transform.position);
            stream.SendNext(transform.rotation);
        }
        else
        {
            //Network player, receive data
            latestPos = (Vector3)stream.ReceiveNext();
            latestRot = (Quaternion)stream.ReceiveNext();
        }
    }

この場合、プレーヤーの位置と回転のみを送信しますが、上記の例を使用して、ネットワーク上で同期する必要がある値を高頻度で送信できます。

受け取った値は void Update() で適用されます。

    // Update is called once per frame
    void Update()
    {
        if (!photonView.isMine)
        {
            //Update remote player (smooth this, this looks good, at the cost of some accuracy)
            transform.position = Vector3.Lerp(transform.position, latestPos, Time.deltaTime * 5);
            transform.rotation = Quaternion.Lerp(transform.rotation, latestRot, Time.deltaTime * 5);
        }
    }

最終的な PlayerNetworkSync.cs スクリプトは次のとおりです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerNetworkSync : Photon.MonoBehaviour
{
    //List of the scripts that should only be active for the local player (ex. PlayerController, MouseLook etc.)
    public MonoBehaviour[] localScripts;
    //List of the GameObjects that should only be active for the local player (ex. Camera, AudioListener etc.)
    public GameObject[] localObject;
    //Values that will be synced over network
    Vector3 latestPos;
    Quaternion latestRot;

    // Use this for initialization
    void Start()
    {
        if (photonView.isMine)
        {
            //Player is local
        }
        else
        {
            //Player is Remote
            for(int i = 0; i < localScripts.Length; i++)
            {
                localScripts[i].enabled = false;
            }
            for (int i = 0; i < localObject.Length; i++)
            {
                localObject[i].SetActive(false);
            }
        }
    }

    void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
    {
        if (stream.isWriting)
        {
            //We own this player: send the others our data
            stream.SendNext(transform.position);
            stream.SendNext(transform.rotation);
        }
        else
        {
            //Network player, receive data
            latestPos = (Vector3)stream.ReceiveNext();
            latestRot = (Quaternion)stream.ReceiveNext();
        }
    }

    // Update is called once per frame
    void Update()
    {
        if (!photonView.isMine)
        {
            //Update remote player (smooth this, this looks good, at the cost of some accuracy)
            transform.position = Vector3.Lerp(transform.position, latestPos, Time.deltaTime * 5);
            transform.rotation = Quaternion.Lerp(transform.rotation, latestRot, Time.deltaTime * 5);
        }
    }
}
  • PlayerNetworkSync.cs スクリプトを して PlayerInstance に追加し、それを PhotonView の監視対象コンポーネントに割り当てます。
  • PlayerCntroller.cs を "Local Scripts" に割り当て、(リモート プレーヤーに対して非アクティブ化する) ゲームオブジェクトを "Local Objects"

  • PlayerInstance を Prefab に保存し、Resources というフォルダーに移動します (そのようなフォルダーがない場合は作成します)。このステップは、ネットワーク上でマルチプレイヤー オブジェクトを生成できるようにするために必要です。

3. ゲームレベルの作成

GameLevel はルームに参加した後に読み込まれるシーンであり、すべてのアクションが発生する場所です。

  • 新しいシーンを作成し、"GameLevel" という名前を付けます (または、別の名前を保持したい場合は、GameLobby.cs のこの行 PhotonNetwork.LoadLevel("GameLevel"); の名前を必ず変更してください)。

私の場合は、プレーンのある単純なシーンを使用します。

  • 次に、新しいスクリプトを作成し、RoomController という名前を付けます。このスクリプトは、ルーム内のロジック (プレーヤーの生成、プレーヤー リストの表示など) を処理します。

必要な変数を定義することから始めましょう。

    //Player instance prefab, must be located in the Resources folder
    public GameObject playerPrefab;
    //Player spawn point
    public Transform spawnPoint;

Player プレハブをインスタンス化するには、PhotonNetwork.Instantiate を使用します。

    // Use this for initialization
    void Start()
    {
        //In case we started this demo with the wrong scene being active, simply load the menu scene
        if (!PhotonNetwork.connected)
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
            return;
        }

        //We're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
        PhotonNetwork.Instantiate(playerPrefab.name, spawnPoint.position, Quaternion.identity, 0);
    }

"Leave Room" ボタンと、ルーム名や接続されているプレイヤーのリストなどの追加要素を備えたシンプルな UI:

    void OnGUI()
    {
        if (PhotonNetwork.room == null)
            return;

        //Leave this Room
        if (GUI.Button(new Rect(5, 5, 125, 25), "Leave Room"))
        {
            PhotonNetwork.LeaveRoom();
        }

        //Show the Room name
        GUI.Label(new Rect(135, 5, 200, 25), PhotonNetwork.room.Name);

        //Show the list of the players connected to this Room
        for (int i = 0; i < PhotonNetwork.playerList.Length; i++)
        {
            //Show if this player is a Master Client. There can only be one Master Client per Room so use this to define the authoritative logic etc.)
            string isMasterClient = (PhotonNetwork.playerList[i].IsMasterClient ? ": MasterClient" : "");
            GUI.Label(new Rect(5, 35 + 30 * i, 200, 25), PhotonNetwork.playerList[i].NickName + isMasterClient);
        }
    }

そして最後に、ルームを出るときに呼び出される OnLeftRoom() という別の PhotonNetwork コールバックを実装します。

    void OnLeftRoom()
    {
        //We have left the Room, return to the MainMenu
        UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
    }

そして、これが最終的な RoomController.cs スクリプトです。

using UnityEngine;

public class RoomController : MonoBehaviour
{
    //Player instance prefab, must be located in the Resources folder
    public GameObject playerPrefab;
    //Player spawn point
    public Transform spawnPoint;

    // Use this for initialization
    void Start()
    {
        //In case we started this demo with the wrong scene being active, simply load the menu scene
        if (!PhotonNetwork.connected)
        {
            UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
            return;
        }

        //We're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
        PhotonNetwork.Instantiate(playerPrefab.name, spawnPoint.position, Quaternion.identity, 0);
    }

    void OnGUI()
    {
        if (PhotonNetwork.room == null)
            return;

        //Leave this Room
        if (GUI.Button(new Rect(5, 5, 125, 25), "Leave Room"))
        {
            PhotonNetwork.LeaveRoom();
        }

        //Show the Room name
        GUI.Label(new Rect(135, 5, 200, 25), PhotonNetwork.room.Name);

        //Show the list of the players connected to this Room
        for (int i = 0; i < PhotonNetwork.playerList.Length; i++)
        {
            //Show if this player is a Master Client. There can only be one Master Client per Room so use this to define the authoritative logic etc.)
            string isMasterClient = (PhotonNetwork.playerList[i].IsMasterClient ? ": MasterClient" : "");
            GUI.Label(new Rect(5, 35 + 30 * i, 200, 25), PhotonNetwork.playerList[i].NickName + isMasterClient);
        }
    }

    void OnLeftRoom()
    {
        //We have left the Room, return to the MainMenu
        UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
    }
}
  • 最後に、GameLevel シーンで新しい GameObject を作成し、それを呼び出します "_RoomController"
  • RoomController スクリプトを _RoomController オブジェクトにアタッチします。
  • PlayerInstance プレハブと SpawnPoint Transform をそれに割り当てて、シーンを保存します
  • MainMenu と GameLevel の両方をビルド設定に追加します。

4. テストビルドの作成

次に、ビルドを作成してテストします。

Sharp Coder ビデオプレーヤー

すべてが期待どおりに機能します。

ボーナス

RPC

Photon Network では、RPC は Remote Procedure Call の略で、同じ部屋にあるリモート クライアントの関数を呼び出すために使用されます (詳細については、こちら を参照してください)。

RPC にはさまざまな用途があります。たとえば、ルーム内のすべてのプレイヤーにチャット メッセージを送信する必要があるとします。RPC を使用すると、それが簡単に行えます。

[PunRPC]
void ChatMessage(string senderName, string messageText)
{
    Debug.Log(string.Format("{0}: {1}", senderName, messageText));
}

関数の前の [PunRPC] に注目してください。この属性は、RPC 経由で関数を呼び出す予定の場合に必要です。

RPC としてマークされた関数を呼び出すには、PhotonView が必要です。呼び出しの例:

PhotonView photonView = PhotonView.Get(this);
photonView.RPC("ChatMessage", PhotonTargets.All, PhotonNetwork.playerName, "Some message");

プロのヒント: スクリプトが Photon.MonoBehaviour または Photon.PunBehaviour の場合は、this.photonView.RPC() を使用できます。

カスタムプロパティ

Photon Network では、カスタム プロパティはプレーヤーまたはルームに割り当てることができるハッシュテーブルです。

これは、頻繁に変更する必要のない永続的なデータを設定する必要がある場合に便利です (例: プレーヤーのチーム名、ルーム ゲーム モードなど)。

まず、ハッシュテーブルを定義する必要があります。これを行うには、スクリプトの先頭に次の行を追加します。

//Replace default Hashtables with Photon hashtables
using Hashtable = ExitGames.Client.Photon.Hashtable; 

以下の例では、"GameMode" および "AnotherProperty" という Room プロパティを設定します。

        //Set Room properties (Only Master Client is allowed to set Room properties)
        if (PhotonNetwork.isMasterClient)
        {
            Hashtable setRoomProperties = new Hashtable();
            setRoomProperties.Add("GameMode", "FFA");
            setRoomProperties.Add("AnotherProperty", "Test");
            PhotonNetwork.room.SetCustomProperties(setRoomProperties);
        }

        //Will print "FFA"
        print((string)PhotonNetwork.room.CustomProperties["GameMode"]);
        //Will print "Test"
        print((string)PhotonNetwork.room.CustomProperties["AnotherProperty"]);

プレーヤーのプロパティも同様に設定されます。

        //Set our Player's property
        Hashtable setPlayerProperties = new Hashtable();
        setPlayerProperties.Add("PlayerHP", (float)100);
        PhotonNetwork.player.SetCustomProperties(setPlayerProperties);

        //Will print "100"
        print((float)PhotonNetwork.player.CustomProperties["PlayerHP"]);

特定のプロパティを削除するには、その値を null に設定するだけです。

        //Remove property called "PlayerHP" from Player properties
        Hashtable setPlayerProperties = new Hashtable();
        setPlayerProperties.Add("PlayerHP", null);
        PhotonNetwork.player.SetCustomProperties(setPlayerProperties);
おすすめの記事
PUN 2 を使用してマルチプレイヤー車ゲームを作成する
Unity が PUN 2 ルームにマルチプレイヤー チャットを追加
PUN 2 を使用して Unity でマルチプレイヤー ゲームを作成する
Unity でマルチプレイヤー ネットワーク ゲームを構築する
マルチプレイヤーのデータ圧縮とビット操作
Unity オンライン リーダーボードのチュートリアル
PUN 2 ラグ補正