Photon Network (Classic) Nybörjarguide
Photon Network är en tjänst för Unity som låter utvecklare skapa flerspelarspel i realtid.
Det ger ett kraftfullt och lättanvänt API som gör det perfekt även för nybörjare.
I det här inlägget kommer vi att köra genom att ladda ner de nödvändiga filerna, ställa in Photon AppID och programmera ett enkelt multiplayer-exempel.
Del 1: Konfigurera Photon Network
Det första steget är att ladda ner Photon Network-paketet från Asset Store. Den innehåller alla nödvändiga skript och filer för integration med flera spelare.
- Öppna ditt Unity-projekt och gå sedan till Asset Store: (Fönster -> Allmänt -> AssetStore) eller tryck på Ctrl+9
- Sök efter "Foton Unity Networking Classic - Gratis" och klicka sedan på det första resultatet eller klicka här
- Importera Photon-paketet efter att nedladdningen är klar
- Efter att paketet har importerats måste du skapa ett Photon App ID, detta görs på deras hemsida: https://www.photonengine.com/
- Skapa ett nytt konto (eller logga in på ditt befintliga konto)
- Gå till applikationssidan genom att klicka på profilikonen och sedan på "Your Applications" eller följ denna länk: https://dashboard.photonengine.com/en-US/PublicCloud
- Klicka på sidan Applikationer "Create new app"
- På sidan för att skapa, välj "Photon Realtime" för Photon Type och för Namn, skriv valfritt namn och klicka sedan på "Create"
Som du kan se använder applikationen gratisplanen som standard. Du kan läsa mer om prisplaner här
- När applikationen har skapats kopierar du app-ID:t under appnamnet
- Gå tillbaka till ditt Unity-projekt och gå sedan till Fönster -> Foton Unity Nätverk -> PUN Wizard
- Klicka på "Setup Project" i PUN Wizard, klistra in ditt app-ID och klicka sedan "Setup Project"
- Photon Network är nu redo
Del 2: Skapa ett spel för flera spelare
Låt oss nu gå till delen där vi faktiskt skapar ett spel för flera spelare.
Sättet multiplayer hanteras i Photon är:
- Först ansluter vi till Photon Region (ex. USA East, Europa, Asien, etc.) som också är känd som Lobby.
- Väl i lobbyn begär vi alla rum som skapas i regionen, sedan kan vi antingen gå med i ett av rummen eller skapa vårt eget rum.
- Efter att vi gick med i rummet begär vi en lista över spelarna som är anslutna till rummet och instansierar deras Player-instanser, som sedan synkroniseras med deras lokala instanser via PhotonView.
- När någon lämnar rummet förstörs deras instans och de tas bort från spelarlistan.
1. Skapa en lobby
Låt oss börja med att skapa en huvudmeny som kommer att innehålla en lobbylogik (bläddra i befintliga rum, skapa nya rum, etc.).
- Skapa en ny scen och kalla den "MainMenu"
- Skapa ett nytt C#-skript och kalla det GameLobby
- Skapa ett nytt GameObject i MainMenu-scenen. Kalla det "_GameLobby" och bifoga GameLobby-skriptet till det
Öppna nu GameLobby-skriptet.
Låt oss först skapa alla nödvändiga 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;
Nästa sak vi behöver göra är att aktivera Auto-Join Lobby och Lobby Stats, detta gör att vi kan ta emot rumslistan. Detta görs i tomrummet Start().
Dessutom aktiverar vi automatisk SyncScene så att scenen synkroniseras automatiskt när vi går med i rummet.
Och slutligen kallar vi PhotonNetwork.ConnectUsingSettings för att ansluta.
// 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);
}
}
För att veta om en anslutning till Photon Cloud lyckades måste vi implementera dessa två callbacks: OnReceivedRoomListUpdate() och OnFailedToConnectToPhoton(objektparametrar).
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();
}
Nästa är UI-delen, där rumssökning och skapande av rum görs:
Och slutligen implementerar vi ytterligare fyra callbacks: OnPhotonCreateRoomFailed(), OnPhotonJoinRoomFailed(objekt[] orsak), OnCreatedRoom() och OnJoinedRoom().
Dessa återuppringningar används för att avgöra om vi gick med/skapade rummet eller om det fanns några problem under anslutningen.
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");
}
Och här är det sista GameLobby.cs-skriptet:
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. Skapa en prefab för spelare
I spel med flera spelare har Player-instansen två sidor: Lokal och Fjärr.
En lokal instans kontrolleras lokalt (av oss).
Fjärrinstans, å andra sidan, är en lokal representation av vad den andra spelaren gör. Det bör vara opåverkat av vår input.
För att avgöra om instansen är lokal eller fjärrstyrd använder vi en PhotonView-komponent.
PhotonView fungerar som en budbärare som tar emot och skickar de värden som behöver synkas, till exempel position och rotation.
Så låt oss börja med att skapa spelarinstansen (om du redan har din spelarinstans redo kan du hoppa över det här steget).
I mitt fall kommer Player-instansen att vara en enkel kub som flyttas med W- och S-tangenterna och roteras med A- och D-tangenterna.
Och här är ett 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);
}
}
}
Nästa steg är att lägga till en PhotonView-komponent.
- Lägg till en PhotonView-komponent till Player Instance
- Skapa ett nytt C#-skript, kalla det PlayerNetworkSync och öppna det (det här skriptet kommer att användas för att kommunicera via PhotonView)
Det första vi behöver göra är att ersätta MonoBehaviour med Photon.MonoBehaviour. Detta steg är nödvändigt för att kunna använda den cachade photonView-variabeln istället för att använda GetComponent<PhotonView>().
public class PlayerNetworkSync : Photon.MonoBehaviour
Efter det kan vi flytta för att skapa alla nödvändiga 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;
Sedan kontrollerar vi i tomrummet Start() om spelaren är Local eller Remote genom att använda 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);
}
}
}
Den faktiska synkroniseringen görs genom PhotonViews återuppringning: 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 det här fallet skickar vi bara spelaren Position och Rotation, men du kan använda exemplet ovan för att skicka valfritt värde som behövs för att synkroniseras över nätverket, med hög frekvens.
Mottagna värden tillämpas sedan 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);
}
}
Här är det sista 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);
}
}
}
- Lägg till PlayerNetworkSync.cs-skriptet till PlayerInstance och tilldela det till PhotonView Observed Components.
- Tilldela PlayerCntroller.cs till "Local Scripts" och tilldela GameObjects (som du vill ska inaktiveras för fjärrspelare) till "Local Objects"
- Spara PlayerInstance till Prefab och flytta den till mappen som heter Resources (Om det inte finns någon sådan mapp, skapa en). Detta steg är nödvändigt för att kunna skapa flerspelarobjekt över nätverket.
3. Skapa en spelnivå
GameLevel är en scen som laddas efter att ha gått med i rummet och det är där all action sker.
- Skapa en ny scen och kalla den "GameLevel" (Eller om du vill behålla ett annat namn, se till att ändra namnet på den här raden PhotonNetwork.LoadLevel("GameLevel"); på GameLobby.cs).
I mitt fall kommer jag att använda en enkel scen med ett plan:
- Skapa nu ett nytt skript och kalla det RoomController. Detta skript kommer att hantera logiken i rummet (som att skapa spelarna, visa spelarlistan, etc.).
Låt oss börja med att definiera de nödvändiga variablerna:
//Player instance prefab, must be located in the Resources folder
public GameObject playerPrefab;
//Player spawn point
public Transform spawnPoint;
För att instansiera Player prefab använder 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);
}
Och ett enkelt användargränssnitt med en "Leave Room"-knapp och några ytterligare element som rumsnamn och listan över anslutna spelare:
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);
}
}
Och slutligen implementerar vi ytterligare ett PhotonNetwork callback som heter OnLeftRoom() som anropas när vi lämnar rummet:
void OnLeftRoom()
{
//We have left the Room, return to the MainMenu
UnityEngine.SceneManagement.SceneManager.LoadScene("MainMenu");
}
Och här är det sista 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");
}
}
- Slutligen, skapa ett nytt GameObject i GameLevel-scenen och kalla det "_RoomController"
- Bifoga RoomController-skriptet till _RoomController-objektet
- Tilldela PlayerInstance prefab och en SpawnPoint Transform till den och spara sedan scenen
- Lägg till både MainMenu och GameLevel till bygginställningarna.
4. Göra ett testbygge
Nu är det dags att bygga och testa den:
Allt fungerar som förväntat!
Bonus
RPC
I Photon Network står RPC för Remote Procedure Call, det används för att anropa en funktion på Remote-klienter som finns i samma rum (du kan läsa mer om det här ).
RPC:er har många användningsområden, låt oss till exempel säga att du behöver skicka ett chattmeddelande till alla spelare i rummet. Med RPC:er är det lätt att göra.
[PunRPC]
void ChatMessage(string senderName, string messageText)
{
Debug.Log(string.Format("{0}: {1}", senderName, messageText));
}
Lägg märke till [PunRPC] före funktionen. Detta attribut är nödvändigt om du planerar att anropa funktionen via RPC:er.
För att anropa funktionerna markerade som RPC behöver du en PhotonView. Exempelsamtal:
PhotonView photonView = PhotonView.Get(this);
photonView.RPC("ChatMessage", PhotonTargets.All, PhotonNetwork.playerName, "Some message");
Proffstips: Om ditt skript är ett Photon.MonoBehaviour eller Photon.PunBehaviour kan du använda: this.photonView.RPC().
Anpassade egenskaper
I Photon Network är Custom Properties en hashtabell som kan tilldelas spelaren eller rummet.
Detta är användbart när du behöver ställa in beständiga data som inte behöver ändras ofta (t.ex. spelarens lagnamn, rumsspelsläge, etc.).
Först måste du definiera en hashtabell, vilket görs genom att lägga till raden nedan i början av skriptet:
//Replace default Hashtables with Photon hashtables
using Hashtable = ExitGames.Client.Photon.Hashtable;
Exemplet nedan anger rumsegenskaperna som heter "GameMode" och "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"]);
Spelaregenskaper ställs in på liknande sätt:
//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"]);
För att ta bort specifik egenskap ställ bara in dess värde till null.
//Remove property called "PlayerHP" from Player properties
Hashtable setPlayerProperties = new Hashtable();
setPlayerProperties.Add("PlayerHP", null);
PhotonNetwork.player.SetCustomProperties(setPlayerProperties);