Photon Unity Networking基础教程 8 网络实例化Player

本节将介绍通过网络实例化Player Prefab,并实现在播放时适应自动场景切换所需的各种功能。

主要内容

  • 实例化Player
  • 追踪Player实例
  • 在竞技场外时管理Player位置

实例化玩家

实际上很容易实例化我们的Player Prefab。我们需要在刚刚进入房间时实例化它,我们可以依靠GameManager脚本的Start()回调,这将表明我们加载了Arena,这意味着我们在一个房间里了。

  1. 打开GameManager脚本

  2. 在Public Variables区块,添加下面的变量

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

     if (playerPrefab == null) {
         Debug.LogError("Missing 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,所以引用将保持完好(与引用层次结构中的GameObject相反,Prefab只能在同一场景中实例化时)。

警告:一定要确保要通过网络实例化的Prefabs是放在Resources文件夹里面的,这是Photon的要求。

然后,在Start()中,我们实例化它(在检查我们有一个正确Prefab Player引用之后)。

注意,我们实例化在地板上方(5个单位以上,而Player只有2个单位高)。当新player加入房间时防止碰撞,Player可能已经在围绕舞台的中心移动,并且因此避免突然的碰撞。“下降”Player也是一个很好的清晰的指示,在游戏中引入了一个新的实体。

然而,这是不够的我们的情况下,我们有一个扭曲:)当其他Player将加入的时候,不同的场景将加载,我们想保持一致性,不能只是因为其中一个离开就破坏现有的Player。因此,我们需要告诉Unity不要销毁我们创建的实例,这反过来意味着,我们需要检查在加载场景时是否需要实例化。

追踪Player实例

  1. 打开PlayerManager脚本

  2. 在Public Variables区块,添加下面的代码

     [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脚本内部实现只在必要时实例化。

  1. 打开GameManager脚本

  2. 把实例化调用部分放到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位置

我们还有一件事要注意。竞技场的尺寸基于玩家的数量而改变,这意味着存在如下情况:如果一个玩家离开,并且其他玩家接近当前竞技场尺寸的边界,那么在加载完小场景之后,他们将发现自己在较小的竞技场之外,我们需要考虑到这一点,并且在这种情况下简单地将Player重新定位到竞技场的中心。这在你的游戏和级别设计时是一个问题。

目前有一个额外的复杂性,因为Unity已经改进了场景管理,并且Unity 5.4已经弃用了一些回调,要创建一个兼容所有Unity版本(从Unity 4.7到最新)的代码,会稍微复杂一些。所以我们需要基于Unity不同版本写不同的代码。它与Photon Networking无关,但无论如何对你掌握项目更新很重要。

  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区块,添加下面两个方法

     #if !UNITY_MIN_5_4
     /// See CalledOnLevelWasLoaded. Outdated in Unity 5.4.
     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脚本

这个新的代码正在监听加载一个级别,从当前玩家的位置和向下发射射线,看看我们是否击中任何东西。如果没有,这意味着我们不在竞技场的地面上,我们需要重新定位回中心,正如我们第一次进入房间。

如果你的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

你可能感兴趣的:(Photon Unity Networking基础教程 8 网络实例化Player)