本节将介绍通过网络实例化Player Prefab,并实现在播放时适应自动场景切换所需的各种功能。
主要内容
- 实例化Player
- 追踪Player实例
- 在竞技场外时管理Player位置
实例化玩家
实际上很容易实例化我们的Player Prefab。我们需要在刚刚进入房间时实例化它,我们可以依靠GameManager脚本的Start()回调,这将表明我们加载了Arena,这意味着我们在一个房间里了。
打开GameManager脚本
-
在Public Variables区块,添加下面的变量
[Tooltip("The prefab to use for representing the player")] public GameObject playerPrefab;
-
在Start()函数中,添加下面的代码
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,所以引用将保持完好(与引用层次结构中的GameObject相反,Prefab只能在同一场景中实例化时)。
警告:一定要确保要通过网络实例化的Prefabs是放在Resources文件夹里面的,这是Photon的要求。
然后,在Start()中,我们实例化它(在检查我们有一个正确Prefab Player引用之后)。
注意,我们实例化在地板上方(5个单位以上,而Player只有2个单位高)。当新player加入房间时防止碰撞,Player可能已经在围绕舞台的中心移动,并且因此避免突然的碰撞。“下降”Player也是一个很好的清晰的指示,在游戏中引入了一个新的实体。
然而,这是不够的我们的情况下,我们有一个扭曲:)当其他Player将加入的时候,不同的场景将加载,我们想保持一致性,不能只是因为其中一个离开就破坏现有的Player。因此,我们需要告诉Unity不要销毁我们创建的实例,这反过来意味着,我们需要检查在加载场景时是否需要实例化。
追踪Player实例
打开PlayerManager脚本
-
在Public Variables区块,添加下面的代码
[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脚本内部实现只在必要时实例化。
打开GameManager脚本
-
把实例化调用部分放到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位置
我们还有一件事要注意。竞技场的尺寸基于玩家的数量而改变,这意味着存在如下情况:如果一个玩家离开,并且其他玩家接近当前竞技场尺寸的边界,那么在加载完小场景之后,他们将发现自己在较小的竞技场之外,我们需要考虑到这一点,并且在这种情况下简单地将Player重新定位到竞技场的中心。这在你的游戏和级别设计时是一个问题。
目前有一个额外的复杂性,因为Unity已经改进了场景管理,并且Unity 5.4已经弃用了一些回调,要创建一个兼容所有Unity版本(从Unity 4.7到最新)的代码,会稍微复杂一些。所以我们需要基于Unity不同版本写不同的代码。它与Photon Networking无关,但无论如何对你掌握项目更新很重要。
打开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区块,添加下面两个方法
#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脚本
这个新的代码正在监听加载一个级别,从当前玩家的位置和向下发射射线,看看我们是否击中任何东西。如果没有,这意味着我们不在竞技场的地面上,我们需要重新定位回中心,正如我们第一次进入房间。
如果你的Unity版本低于Unity 5.4,我们将使用Unity的回调OnLevelWasLoaded。如果你是Unity 5.4或更高版本,OnLevelWasLoaded不再可用,而是必须使用新的SceneManagement系统。最后,为了避免重复代码,我们只需要调用CalledOnLevelWasLoaded()方法,该方法将从OnLevelWasLoaded或SceneManager sceneLoaded回调中调用。
原文
http://doc.photonengine.com/en-us/pun/current/tutorials/pun-basics-tutorial/player-instantiation