Photon Unity Networking基礎(chǔ)教程 8 網(wǎng)絡(luò)實例化Player

本節(jié)將介紹通過網(wǎng)絡(luò)實例化Player Prefab,并實現(xiàn)在播放時適應(yīng)自動場景切換所需的各種功能。

主要內(nèi)容

  • 實例化Player
  • 追蹤Player實例
  • 在競技場外時管理Player位置

實例化玩家

實際上很容易實例化我們的Player Prefab。我們需要在剛剛進(jìn)入房間時實例化它,我們可以依靠GameManager腳本的Start()回調(diào),這將表明我們加載了Arena,這意味著我們在一個房間里了。

  1. 打開GameManager腳本

  2. 在Public Variables區(qū)塊,添加下面的變量

     [Tooltip("The prefab to use for representing the player")]
     public GameObject playerPrefab;
    
  3. 在Start()函數(shù)中,添加下面的代碼

     if (playerPrefab == null) {
         Debug.LogError("<Color=Red><a>Missing</a></Color> playerPrefab Reference. Please set it up in GameObject 'Game Manager'",this);
     } else {
         Debug.Log("We are Instantiating LocalPlayer from "+Application.loadedLevelName);
     // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
         PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0);
     }
    
  4. 保存腳本

這暴露了一個公共字段讓你引用Player Prefab,它很方便,因為在這個特別的,我們可以直接拖放在GameManager Prefab上,而不是在每個場景,因為Player Prefab是一個Asset,所以引用將保持完好(與引用層次結(jié)構(gòu)中的GameObject相反,Prefab只能在同一場景中實例化時)。

警告:一定要確保要通過網(wǎng)絡(luò)實例化的Prefabs是放在Resources文件夾里面的,這是Photon的要求。

然后,在Start()中,我們實例化它(在檢查我們有一個正確Prefab Player引用之后)。

注意,我們實例化在地板上方(5個單位以上,而Player只有2個單位高)。當(dāng)新player加入房間時防止碰撞,Player可能已經(jīng)在圍繞舞臺的中心移動,并且因此避免突然的碰撞?!跋陆怠盤layer也是一個很好的清晰的指示,在游戲中引入了一個新的實體。

然而,這是不夠的我們的情況下,我們有一個扭曲:)當(dāng)其他Player將加入的時候,不同的場景將加載,我們想保持一致性,不能只是因為其中一個離開就破壞現(xiàn)有的Player。因此,我們需要告訴Unity不要銷毀我們創(chuàng)建的實例,這反過來意味著,我們需要檢查在加載場景時是否需要實例化。

追蹤Player實例

  1. 打開PlayerManager腳本

  2. 在Public Variables區(qū)塊,添加下面的代碼

     [Tooltip("The local player instance. Use this to know if the local player is represented in the Scene")]
     public static GameObject LocalPlayerInstance;
    
  3. 在Awake()中添加下面的代碼

     // #Important
     // used in GameManager.cs: we keep track of the localPlayer instance to prevent instantiation when levels are synchronized
     if ( photonView.isMine)
     {
         PlayerManager.LocalPlayerInstance = this.gameObject;
     }
     // #Critical
     // we flag as don't destroy on load so that instance survives level synchronization, thus giving a seamless experience when levels load.
     DontDestroyOnLoad(this.gameObject);
    
  4. 保存腳本

修改完這些,然后我們在GameManager腳本內(nèi)部實現(xiàn)只在必要時實例化。

  1. 打開GameManager腳本

  2. 把實例化調(diào)用部分放到if語句中

     if (PlayerManager.LocalPlayerInstance==null)
     {
         Debug.Log("We are Instantiating LocalPlayer from "+Application.loadedLevelName);
         // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
         PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0);
     }else{
         Debug.Log("Ignoring scene load for "+Application.loadedLevelName);
     }
    
  3. 保存腳本

這樣的話,如果PlayerManager中LocalPlayerInstance為空的話,才會實例化。

在競技場外時管理Player位置

我們還有一件事要注意。競技場的尺寸基于玩家的數(shù)量而改變,這意味著存在如下情況:如果一個玩家離開,并且其他玩家接近當(dāng)前競技場尺寸的邊界,那么在加載完小場景之后,他們將發(fā)現(xiàn)自己在較小的競技場之外,我們需要考慮到這一點,并且在這種情況下簡單地將Player重新定位到競技場的中心。這在你的游戲和級別設(shè)計時是一個問題。

目前有一個額外的復(fù)雜性,因為Unity已經(jīng)改進(jìn)了場景管理,并且Unity 5.4已經(jīng)棄用了一些回調(diào),要創(chuàng)建一個兼容所有Unity版本(從Unity 4.7到最新)的代碼,會稍微復(fù)雜一些。所以我們需要基于Unity不同版本寫不同的代碼。它與Photon Networking無關(guān),但無論如何對你掌握項目更新很重要。

  1. 打開PlayerManager腳本

  2. 在頂部添加下面的代碼

     #if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && ! UNITY_5_3) || UNITY_6
     #define UNITY_MIN_5_4
     #endif
    
  3. 在Start()方法末尾,添加下面的代碼

     #if UNITY_MIN_5_4
     // Unity 5.4 has a new scene management. register a method to call CalledOnLevelWasLoaded.
     UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) =>
             {
                 this.CalledOnLevelWasLoaded(scene.buildIndex);
             };
     #endif
    
  4. 在MonoBehaviour CallBacks區(qū)塊,添加下面兩個方法

     #if !UNITY_MIN_5_4
     /// <summary>See CalledOnLevelWasLoaded. Outdated in Unity 5.4.</summary>
     void OnLevelWasLoaded(int level)
     {
     this.CalledOnLevelWasLoaded(level);
     }
     #endif         
      
     void CalledOnLevelWasLoaded(int level)
     {
         // check if we are outside the Arena and if it's the case, spawn around the center of the arena in a safe zone
         if (!Physics.Raycast(transform.position, -Vector3.up, 5f))
         {
             transform.position = new Vector3(0f, 5f, 0f);
         }
     }
    
  5. 保存PlayerManager腳本

這個新的代碼正在監(jiān)聽加載一個級別,從當(dāng)前玩家的位置和向下發(fā)射射線,看看我們是否擊中任何東西。如果沒有,這意味著我們不在競技場的地面上,我們需要重新定位回中心,正如我們第一次進(jìn)入房間。

如果你的Unity版本低于Unity 5.4,我們將使用Unity的回調(diào)OnLevelWasLoaded。如果你是Unity 5.4或更高版本,OnLevelWasLoaded不再可用,而是必須使用新的SceneManagement系統(tǒng)。最后,為了避免重復(fù)代碼,我們只需要調(diào)用CalledOnLevelWasLoaded()方法,該方法將從OnLevelWasLoaded或SceneManager sceneLoaded回調(diào)中調(diào)用。

原文

http://doc.photonengine.com/en-us/pun/current/tutorials/pun-basics-tutorial/player-instantiation

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容