מדריך למתחילים של Photon Network (קלאסי).

Photon Network הוא שירות עבור Unity המאפשר למפתחים ליצור משחקים מרובי משתתפים בזמן אמת.

הוא מספק API חזק וקל לשימוש שהופך אותו למושלם אפילו למפתחים מתחילים.

בפוסט זה, נעבור על הורדת הקבצים הדרושים, הגדרת Photon AppID ותכנות דוגמה פשוטה של ​​מרובה משתתפים.

חלק 1: הגדרת רשת פוטון

השלב הראשון הוא להוריד את חבילת Photon Network מה-Asset Store. הוא מכיל את כל התסריטים והקבצים הדרושים לשילוב מרובה משתתפים.

  • פתח את הפרויקט Unity שלך ואז עבור אל ה-Asset Store: (חלון -> כללי -> AssetStore) או הקש Ctrl+9
  • חפש "Photon Unity Networking Classic - Free" ולאחר מכן לחץ על התוצאה הראשונה או לחץ כאן
  • ייבא את חבילת Photon לאחר סיום ההורדה

  • לאחר ייבוא ​​החבילה עליך ליצור מזהה אפליקציית Photon, זה נעשה באתר האינטרנט שלהם: https://www.photonengine.com/
  • צור חשבון חדש (או היכנס לחשבון הקיים שלך)
  • עבור לדף היישומים על ידי לחיצה על סמל הפרופיל ולאחר מכן על "Your Applications" או עקוב אחר הקישור הזה: https://dashboard.photonengine.com/en-US/PublicCloud
  • בדף יישומים לחץ "Create new app"

  • בדף היצירה, עבור סוג פוטון בחר "Photon Realtime" ועבור השם, הקלד כל שם ולאחר מכן לחץ על "Create"

כפי שאתה יכול לראות, היישום כברירת מחדל לתוכנית החינמית. תוכל לקרוא עוד על תוכניות תמחור כאן

  • לאחר יצירת האפליקציה, העתק את מזהה האפליקציה שנמצא מתחת לשם האפליקציה

  • חזור לפרויקט Unity שלך ואז עבור אל חלון -> פוטון Unity רשת -> אשף PUN
  • באשף PUN לחץ על "Setup Project", הדבק את מזהה האפליקציה שלך ולאחר מכן לחץ "Setup Project"
  • רשת הפוטון מוכנה כעת

חלק 2: יצירת משחק מרובה משתתפים

כעת נעבור לחלק בו אנו יוצרים למעשה משחק מרובה משתתפים.

הדרך שבה מתנהל מרובה משתתפים בפוטון היא:

  • ראשית, אנו מתחברים לאזור הפוטון (לדוגמה, מזרח ארה"ב, אירופה, אסיה וכו') אשר ידוע גם בשם לובי.
  • ברגע שנכנסים ללובי, אנו מבקשים את כל החדרים שנוצרו באזור, ואז נוכל להצטרף לאחד מהחדרים או ליצור חדר משלנו.
  • לאחר שהצטרפנו לחדר אנו מבקשים רשימה של השחקנים המחוברים לחדר ומציגים את מופעי ה-Player שלהם, אשר לאחר מכן מסונכרנים עם המופעים המקומיים שלהם באמצעות 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().

כמו כן, אנו מפעילים אוטומטית SyncScene כך שהסצנה תסונכרן אוטומטית ברגע שאנו מצטרפים לחדר.

ולבסוף, אנו קוראים 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 הצליח, עלינו ליישם את 2 ההתקשרויות הבאות: OnReceivedRoomListUpdate() ו-OnFailedToConnectToPhoton(פרמטרי אובייקט).

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

הבא הוא החלק של ממשק המשתמש, שבו מתבצעות הגלישה בחדר ויצירת החדר:

הלובי של רשת פוטון

ולבסוף אנו מיישמים עוד 4 התקשרויות חוזרות: OnPhotonCreateRoomFailed(), OnPhotonJoinRoomFailed(אובייקט[] סיבה), 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 יש 2 צדדים: מקומי ומרוחק.

מופע מקומי נשלט באופן מקומי (על ידינו).

מופע מרחוק, לעומת זאת, הוא ייצוג מקומי של מה שהשחקן השני עושה. זה לא אמור להיות מושפע מהקלט שלנו.

כדי לקבוע אם המופע הוא מקומי או מרוחק אנו משתמשים ברכיב PhotonView.

PhotonView פועל כשליח שמקבל ושולח את הערכים שצריך לסנכרן, למשל מיקום וסיבוב.

אז בואו נתחיל ביצירת מופע הנגן (אם כבר יש לכם מופע הנגן מוכן, תוכלו לדלג על שלב זה).

במקרה שלי, המופע של Player יהיה קובייה פשוטה שמוזזת עם מקשי W, ו-S ומסתובבים עם מקשי A ו-D.

מופע נגן רשת 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. שלב זה נחוץ כדי להיות מסוגל להשתמש במשתנה photonView המאוחסן במטמון במקום להשתמש ב-GetComponent<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;

לאחר מכן בריק 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, מידע PhotonMessageInfo):

    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 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 Observed.
  • הקצה את ה-PlayerCntroller.cs ל-"Local Scripts" והקצה את ה-GameObjects (שאותם רוצים לנטרל עבור שחקנים מרוחקים) ל- "Local Objects"

  • שמור את PlayerInstance ל-Prefab והעבר אותו לתיקיה שנקראת Resources (אם אין תיקיה כזו, צור אחת). שלב זה נחוץ כדי להיות מסוגל להריץ אובייקטים מרובי משתתפים ברשת.

3. יצירת רמת משחק

GameLevel היא סצנה שנטענת לאחר ההצטרפות לחדר ושם מתרחשת כל האקשן.

  • צור סצנה חדשה וקרא לה "GameLevel" (או אם אתה רוצה לשמור שם אחר, הקפד לשנות את השם בשורה זו PhotonNetwork.LoadLevel("GameLevel"); ב-GameLobby.cs).

במקרה שלי, אני אשתמש בסצנה פשוטה עם מטוס:

  • כעת צור סקריפט חדש וקרא לו RoomController. הסקריפט הזה יטפל בהיגיון בתוך החדר (כמו השרצת השחקנים, הצגת רשימת השחקנים וכו').

נתחיל בהגדרת המשתנים הדרושים:

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

כדי להפעיל את הגרסה המוקדמת של הנגן אנו משתמשים ב-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" וכמה אלמנטים נוספים כגון שם החדר ורשימת השחקנים המחוברים:

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

ולבסוף, אנו מיישמים התקשרות חוזרת נוספת של PhotonNetwork בשם OnLeftRoom() שנקראת כשאנחנו עוזבים את החדר:

    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");
    }
}
  • לבסוף, צור GameObject חדש בסצנת GameLevel וקרא לו "_RoomController"
  • צרף את הסקריפט של RoomController לאובייקט _RoomController
  • הקצה לו את ה-PlayerInstance הקדם ו-SpawnPoint Transform ואז שמור את הסצנה
  • הוסף גם MainMenu וגם GameLevel להגדרות ה-Build.

4. ביצוע מבחן Build

עכשיו הגיע הזמן ליצור מבנה ולבדוק אותו:

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] לפני הפונקציה. תכונה זו נחוצה אם אתה מתכנן לקרוא לפונקציה באמצעות RPCs.

כדי לקרוא לפונקציות המסומנות כ-RPC, אתה צריך PhotonView. שיחה לדוגמה:

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

טיפ מקצוען: אם הסקריפט שלך הוא Photon.MonoBehaviour או Photon.PunBehaviour, אתה יכול להשתמש ב: this.photonView.RPC().

מאפיינים מותאמים אישית

ברשת Photon, מאפיינים מותאמים אישית הוא Hashtable שניתן להקצות לנגן או לחדר.

זה שימושי כאשר אתה צריך להגדיר נתונים קבועים שאין צורך לשנות לעתים קרובות (למשל שם צוות שחקן, מצב משחק חדר וכו').

ראשית, עליך להגדיר Hashtable, אשר נעשה על ידי הוספת השורה למטה בתחילת הסקריפט:

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

הדוגמה שלהלן מגדירה את מאפייני החדר בשם "GameMode" ו-"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"]);

מאפייני הנגן מוגדרים באופן דומה:

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