本節(jié)將介紹通過網(wǎng)絡(luò)實例化Player Prefab,并實現(xiàn)在播放時適應(yīng)自動場景切換所需的各種功能。
主要內(nèi)容
- 實例化Player
- 追蹤Player實例
- 在競技場外時管理Player位置
實例化玩家
實際上很容易實例化我們的Player Prefab。我們需要在剛剛進(jìn)入房間時實例化它,我們可以依靠GameManager腳本的Start()回調(diào),這將表明我們加載了Arena,這意味著我們在一個房間里了。
打開GameManager腳本
-
在Public Variables區(qū)塊,添加下面的變量
[Tooltip("The prefab to use for representing the player")] public GameObject playerPrefab; -
在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); } 保存腳本
這暴露了一個公共字段讓你引用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實例
打開PlayerManager腳本
-
在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; -
在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); 保存腳本
修改完這些,然后我們在GameManager腳本內(nèi)部實現(xiàn)只在必要時實例化。
打開GameManager腳本
-
把實例化調(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); } 保存腳本
這樣的話,如果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),但無論如何對你掌握項目更新很重要。
打開PlayerManager腳本
-
在頂部添加下面的代碼
#if UNITY_5 && (!UNITY_5_0 && !UNITY_5_1 && !UNITY_5_2 && ! UNITY_5_3) || UNITY_6 #define UNITY_MIN_5_4 #endif -
在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 -
在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); } } 保存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