Photon Network (klassisk) nybegynnerveiledning

Photon Network er en tjeneste for Unity som lar utviklere lage flerspillerspill i sanntid.

Den gir en kraftig og brukervennlig API som gjør den perfekt selv for nybegynnere.

I dette innlegget vil vi kjøre gjennom å laste ned de nødvendige filene, sette opp Photon AppID og programmere et enkelt flerspillereksempel.

Del 1: Sette opp Photon Network

Det første trinnet er å laste ned Photon Network-pakken fra Asset Store. Den inneholder alle nødvendige skript og filer for flerspillerintegrasjon.

  • Åpne Unity-prosjektet og gå til Asset Store: (Vindu -> Generelt -> AssetStore) eller trykk Ctrl+9
  • Søk etter "Foto Unity Networking Classic - Gratis" og klikk deretter på det første resultatet eller klikk her
  • Importer Photon-pakken etter at nedlastingen er fullført

  • På opprettingssiden, for Photon Type velg "Photon Realtime" og for navnet, skriv inn et hvilket som helst navn og klikk "Create"

Som du kan se, bruker applikasjonen gratisplanen som standard. Du kan lese mer om prisplaner her

  • Når applikasjonen er opprettet, kopierer du app-ID-en som ligger under app-navnet

  • Gå tilbake til Unity-prosjektet ditt og gå til Vindu -> Foton Unity Nettverk -> PUN-veiviser
  • I PUN Wizard klikker du på "Setup Project", limer du inn app-ID-en din og klikker "Setup Project"
  • Photon Network er nå klart

Del 2: Lage et flerspillerspill

La oss nå gå til delen der vi faktisk lager et flerspillerspill.

Måten flerspiller håndteres i Photon er:

  • Først kobler vi til Photon Region (eks. USA Øst, Europa, Asia, etc.) som også er kjent som Lobby.
  • En gang i lobbyen ber vi om alle rommene som er opprettet i regionen, så kan vi enten bli med i et av rommene eller lage vårt eget rom.
  • Etter at vi ble med i rommet ber vi om en liste over spillerne som er koblet til rommet og instansierer deres spillerforekomster, som deretter synkroniseres med deres lokale forekomster gjennom PhotonView.
  • Når noen forlater rommet, blir instansen deres ødelagt og de fjernes fra spillerlisten.

1. Sette opp en lobby

La oss starte med å lage en hovedmeny som vil inneholde en lobbylogikk (bla gjennom eksisterende rom, opprette nye rom osv.).

  • Lag en ny scene og ring den "MainMenu"
  • Lag et nytt C#-skript og kall det GameLobby
  • Lag et nytt GameObject i MainMenu-scenen. Kall det "_GameLobby" og legg ved GameLobby-skriptet til det

Åpne nå GameLobby-skriptet.

Først, la oss lage alle nødvendige variabler:

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

Det neste vi må gjøre er å aktivere Auto-Join Lobby og Lobby Stats, dette vil tillate oss å motta romlisten. Dette gjøres i tomrommet Start().

Dessuten aktiverer vi automatisk SyncScene slik at scenen synkroniseres automatisk når vi blir med i rommet.

Og til slutt kaller vi PhotonNetwork.ConnectUsingSettings for å koble til.

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

For å vite om en tilkobling til Photon Cloud var vellykket, må vi implementere disse to tilbakekallingene: OnReceivedRoomListUpdate() og OnFailedToConnectToPhoton(objektparametere).

    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();
    }

Neste er UI-delen, der romsurfing og romoppretting gjøres:

Photon Network lobby

Og til slutt implementerer vi ytterligere 4 tilbakeringinger: OnPhotonCreateRoomFailed(), OnPhotonJoinRoomFailed(objekt[] årsak), OnCreatedRoom() og OnJoinedRoom().

Disse tilbakeringingene brukes til å avgjøre om vi ble med/opprettet rommet eller om det var noen problemer under forbindelsen.

    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");
    }

Og her er det siste GameLobby.cs manuset:

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. Opprette en prefabrikert spiller

I flerspillerspill har Player-forekomsten 2 sider: lokal og ekstern.

En lokal instans kontrolleres lokalt (av oss).

Ekstern forekomst, derimot, er en lokal representasjon av hva den andre spilleren gjør. Det skal være upåvirket av våre innspill.

For å finne ut om forekomsten er lokal eller ekstern, bruker vi en PhotonView-komponent.

PhotonView fungerer som en messenger som mottar og sender verdiene som må synkroniseres, for eksempel posisjon og rotasjon.

Så la oss begynne med å lage spillerforekomsten (Hvis du allerede har spillerforekomsten klar, kan du hoppe over dette trinnet).

I mitt tilfelle vil Player-forekomsten være en enkel kube som flyttes med W- og S-tastene og roteres med A- og D-tastene.

Photon Network Player-forekomst

Og her er et enkelt kontrollerskript:

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

Det neste trinnet er å legge til en PhotonView-komponent.

  • Legg til en PhotonView-komponent til spillerforekomsten
  • Lag et nytt C#-skript, kall det PlayerNetworkSync, og åpne det (dette skriptet vil bli brukt til å kommunisere gjennom PhotonView)

Det første vi må gjøre er å erstatte MonoBehaviour med Photon.MonoBehaviour. Dette trinnet er nødvendig for å kunne bruke den bufrede photonView-variabelen i stedet for å bruke GetComponent<PhotonView>().

public class PlayerNetworkSync : Photon.MonoBehaviour

Etter det kan vi flytte for å lage alle nødvendige variabler:

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

Så i tomrommet Start() sjekker vi om spilleren er lokal eller ekstern ved å bruke 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);
            }
        }
    }

Selve synkroniseringen gjøres gjennom PhotonViews tilbakeringing: OnPhotonSerializeView(PhotonStream-strøm, 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();
        }
    }

I dette tilfellet sender vi bare spillerens posisjon og rotasjon, men du kan bruke eksemplet ovenfor til å sende en hvilken som helst verdi som er nødvendig for å bli synkronisert over nettverket, med høy frekvens.

Mottatte verdier blir deretter brukt i 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);
        }
    }

Her er det siste PlayerNetworkSync.cs-skriptet:

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);
        }
    }
}
  • Legg PlayerNetworkSync.cs-skriptet til PlayerInstance og tilordne det til PhotonView Observed Components.
  • Tilordne PlayerCntroller.cs til "Local Scripts" og tilordne GameObjects (som du ønsker skal deaktiveres for eksterne spillere) til "Local Objects"

  • Lagre PlayerInstance til Prefab og flytt den til mappen som heter Resources (Hvis det ikke finnes en slik mappe, lag en). Dette trinnet er nødvendig for å kunne skape flerspillerobjekter over nettverket.

3. Opprette et spillnivå

GameLevel er en scene som lastes inn etter å ha blitt med i rommet, og det er der all handlingen skjer.

  • Lag en ny scene og kall den "GameLevel" (Eller hvis du vil beholde et annet navn, sørg for å endre navnet på denne linjen PhotonNetwork.LoadLevel("GameLevel"); på GameLobby.cs).

I mitt tilfelle vil jeg bruke en enkel scene med et fly:

  • Lag et nytt skript og kall det RoomController. Dette skriptet vil håndtere logikken inne i rommet (som å gyte spillerne, vise spillerlisten, etc.).

La oss starte med å definere de nødvendige variablene:

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

For å instansiere Player prefab bruker vi 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);
    }

Og et enkelt brukergrensesnitt med en "Leave Room"-knapp og noen tilleggselementer som romnavn og listen over tilkoblede spillere:

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

Og til slutt implementerer vi en annen PhotonNetwork callback kalt OnLeftRoom() som kalles når vi forlater rommet:

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

Og her er det siste RoomController.cs-skriptet:

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");
    }
}
  • Til slutt, lag et nytt GameObject i GameLevel-scenen og kall det "_RoomController"
  • Fest RoomController-skriptet til _RoomController-objektet
  • Tilordne PlayerInstance-prefabrikken og en SpawnPoint-transformasjon til den, og lagre deretter scenen
  • Legg til både MainMenu og GameLevel i byggeinnstillingene.

4. Lage et testbygg

Nå er det på tide å lage en build og teste den:

Sharp Coder Videospiller

Alt fungerer som forventet!

Bonus

RPC

I Photon Network står RPC for Remote Procedure Call, det brukes til å kalle opp en funksjon på Remote-klienter som er i samme rom (Du kan lese mer om det her ).

RPC-er har mange bruksområder, for eksempel, la oss si at du må sende en chatmelding til alle spillerne i rommet. Med RPC-er er det enkelt å gjøre.

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

Legg merke til [PunRPC] før funksjonen. Dette attributtet er nødvendig hvis du planlegger å kalle funksjonen via RPCer.

For å kalle opp funksjonene merket som RPC, trenger du en PhotonView. Eksempelanrop:

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

Profftips: Hvis skriptet ditt er et Photon.MonoBehaviour eller Photon.PunBehaviour kan du bruke: this.photonView.RPC().

Egenskaper

I Photon Network er Custom Properties en hashtabell som kan tilordnes spilleren eller rommet.

Dette er nyttig når du trenger å angi vedvarende data som ikke trenger å endres ofte (f.eks. spillerlagsnavn, romspillmodus osv.).

Først må du definere en hashtabell, som gjøres ved å legge til linjen nedenfor i begynnelsen av skriptet:

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

Eksemplet nedenfor setter romegenskapene kalt "GameMode" og "AnotherProperty":

        //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"]);

Spilleregenskapene er satt på samme måte:

        //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"]);

For å fjerne en spesifikk egenskap, sett bare verdien til null.

        //Remove property called "PlayerHP" from Player properties
        Hashtable setPlayerProperties = new Hashtable();
        setPlayerProperties.Add("PlayerHP", null);
        PhotonNetwork.player.SetCustomProperties(setPlayerProperties);
Foreslåtte artikler
Lag et bilspill med flere spillere med PUN 2
Bygg flerspillernettverksspill i Unity
Unity legger til flerspillerchat til PUN 2-rommene
Synkroniser rigidbodies over nettverk ved hjelp av PUN 2
Lag et flerspillerspill i Unity med PUN 2
Multiplayer datakomprimering og bitmanipulering
Unity Online Leaderboard-opplæring