Photon Unity Networking基础教程 7 修改Player的联网版本

Photon Unity Networking基础教程 7 修改Player的联网版本

本节将指导您修改Player Prefab。我们首先创建一个可以工作的player,但现在我们将修改它,以便它在PUN环境中使用时能正常工作。修改很少的代码,但概念是至关重要的。所以这一节非常重要。

主要内容

  • PhotonView 组件
  • Transform 同步
  • Animator 同步
  • 用户输入管理
  • Camera 控制
  • Beams 开火控制
  • Health 同步

PhotonView 组件

首先,我们需要在Prefab上添加一个PhotonView组件。PhotonView将每个计算机上的各种实例连接在一起,并定义要观察的组件以及如何观察这些组件。

  • 添加PhotonView组件到My Robot Kyle
  • 将Observe Option设置为Unreliable On Change
  • 注意,PhotonView警告你,要起作用的话你需要观察一些东西

让我们设置我们要观察的对象,然后我们将回到这个PhotonView组件,并完成它的设置。

Transform 同步

我们想要同步的明显特征是角色的位置和旋转,使得当Player移动时,其他计算机上的Player也以类似的方式移动和旋转。

你可以直接观察自己脚本中的Transform组件,但是由于网络延迟和数据同步的有效性,你会遇到很多麻烦。幸运的是,为了使这个常见的任务更容易,我们将使用[Photon Transform View]组件,作为变换组件和PhotonView之间的中间人(middleMan)。基本上,这个组件已经为你做了所有的工作。

  1. 给'My Robot Kyle'Prefab添加PhotonTransformView
  2. 拖拽PhotonTransformView的标题栏到PhotonView组件的第一个Observable组件上
ObservePhotonTransformView.gif
  1. 在PhotonTransformView组件上勾选Synchronize Position
  2. 在Synchronize Position里面,Interpolation Option选择“Lerp”
  3. 把Lerp Speed设置为10(数值越大插值越快)
  4. 勾选SynchronizeRotation
PrefabPhotonTransformView.png
提示:注意右边的蓝色书本帮助链接,点击它能获取信息,学习不同的设置和效果。
PrefabPhotonTransformViewHelp.png

Animator 同步

PhotonAnimatorView也使得网络设置变得轻而易举,将为您节省大量的时间和麻烦。它允许您定义哪些层权重和要同步的参数。层权重只有在游戏过程中改变了才需要同步,并且可以不同步它们。参数也是如此。有时可以从其他因素导出动画值。速度值是一个很好的例子,你不一定需要让这个值完全同步,但你可以使用同步的位置更新来估计它的值。如果可能,尝试同步尽可能少的参数。

  1. 给My Robot Kyle Prefab添加一个PhotonAnimatorView
  2. 拖拽PhotonAnimatorView的标题栏到PhotonView组件的Observable组件上
  3. 同步参数中设置Speed为Discrete
  4. 设置Direction为Discrete
  5. 设置Jump为Discrete
  6. 设置Hi为Disabled
ObservePhotonAnimatorView.gif

每个值都可以是disabled,或者以离散(discretely)或连续(continuously)的方式同步(synchronized)。在我们的例子中,由于我们不使用Hi参数,我们将禁用它,从而节省带宽。

离散同步(Discrete synchronization)意味着值每秒发送10次(在OnPhotonSerializeView中)。 接收客户端将值传递到他们的本地Animator。

连续同步(Continuous synchronization)意味着PhotonAnimatorView每帧都要运行。当调用OnPhotonSerializeView(每秒10次)时,自上次调用以来记录的值一起发送。接收客户端然后按顺序应用值以保持平滑过渡。虽然此模式更平滑,但它为了实现此效果发送了更多数据。

用户输入管理

用户控制网络的一个关键方面是,相同的Prefab将为所有玩家实例化,但是其中只有一个是实际在计算机前的用户控制的,所有其他实例代表的是在其他计算机上的其他用户。因此,这一点的第一个障碍是输入管理。我们如何能够在一个实例上而不是在其他实例上启用输入,以及如何知道哪个是正确的?这就需要isMine的概念。

让我们编辑我们之前创建的PlayerAnimatorManager脚本。在目前的形式中,这个脚本不知道这个区别,让我们实现它。

  1. 打开脚本PlayerAnimatorManager

  2. 把PlayerAnimatorManager的基类改为Photon.MonoBehaviour,这个类很方便的暴露photonView的组件

  3. 在Update函数的开头加入下面代码

     if( photonView.isMine == false && PhotonNetwork.connected == true )
     {
         return;
     }
    
  4. 保存脚本

Ok,如果实例由“客户端”应用程序控制,PhotonView.isMine将为true,意味着此实例表示在此应用程序中在此计算机上正在play的玩家。因此,如果它是假的,我们不想做任何事情,只依靠PhotonView组件来同步我们之前设置的变换和动画组件。

但是,为什么在我们的if语句中强制执行PhotonNetwork.connected == true?因为在开发期间,我们可能想要测试这个prefab,而不连接。在虚拟场景中,例如,只是创建和验证与网络功能无关的代码。因此,使用这个附加表达式,如果我们没有连接,我们将允许使用输入。这是一个非常简单的伎俩,并将大大改善您的开发过程中的工作流。

Camera 控制

它和输入一样,Player只有一个游戏视图,所以我们需要CameraWork脚本只跟随本地Player,而不是其他Player。这就是为什么CameraWork脚本有这个能力来定义什么时候跟随。

让我们修改PlayerManager脚本来控制CameraWork组件。

  1. 打开PlayerManager脚本

  2. 在Awake()和Update()函数之间插入下面的代码

     /// <summary>
     /// MonoBehaviour method called on GameObject by Unity during initialization phase.
     /// </summary>
     void Start()
     {
         CameraWork _cameraWork = this.gameObject.GetComponent<CameraWork>(); 
         if (_cameraWork!=null )
         {
             if ( photonView.isMine)
             {
                 _cameraWork.OnStartFollowing();
             }
         }else{
             Debug.LogError("<Color=Red><a>Missing</a></Color> CameraWork Component on playerPrefab.",this);
         }
     }
    
  3. 保存脚本

首先,它获取CameraWork组件,我们期望这样,所以如果我们没有找到它,就记录一个错误。然后,如果photonView.isMine为true,这意味着我们需要跟随这个实例,因此我们调用_cameraWork.OnStartFollowing(),它有效地使相机跟随场景中的那个实例。

所有其他Player实例的photonView.isMine将设置为false,因此它们各自的_cameraWork将不会做任何事情。

下面的一个改变可以使这点生效

  1. 在Robot animator prefab上,CameraWork组件中禁用Follow on Start属性
CameraWorkFollowOnStartOff.png

PlayerManager脚本将会像上面描述的那样调用_cameraWork.OnStartFollowing(),现在这有效的处理了跟随Player的逻辑。

Beams 开火控制

开火也同样遵循上面的输入原则,它只在photonView.isMine是true的情况下工作。

  1. 打开PlayerManager脚本

  2. 用一个if语句包住输入处理

     if (photonView.isMine) {
         ProcessInputs ();
     }
    
  3. 保存脚本

然而,当测试这个的时候,我们只看到本地Player开火。我们需要看看其他实例何时开火!我们需要一种用于在网络上同步开火的机制。为此,我们将手动同步IsFiring布尔值,直到现在,我们离开了PhotonTransformView和PhotonAnimatorView来为我们进行变量的所有内部同步,我们只需要调整通过Unity Inspector方便地暴露给我们的参数,但在这里我们需要的是,针对你的具体游戏,所以我们需要手动这样做。

  1. 打开PlayerManager脚本
  2. 实现IPunObservable接口
PlayerManagerIpunObsverableImplementation.gif
  1. 在IPunObservable.OnPhotonSerializeView函数中添加下面代码

     if (stream.isWriting)
     {
         // We own this player: send the others our data
         stream.SendNext(IsFiring);
     }else{
         // Network player, receive data
         this.IsFiring = (bool)stream.ReceiveNext();
     }
    
  2. 保存脚本

  3. 回到Unity编辑器,在assets中选择Robot Animator prefab,在PhotonView组件中添加一条监视记录,然后把PlayerManager组件拖拽到上面

PrefabObservePlayerManager.png

没有上一步的话,IPunObservable.OnPhotonSerializeView永远不会调用,因为它没有被PhotonView监视。

在这个IPunObservable.OnPhotonSerializeView方法中,我们传递了一个变量stream,这是将通过网络发送的,并且这个调用是我们读写数据的机会。当我们是本地Player的时候(PhotonView.isMine == true)才能写入数据,否则是读数据。

由于stream类自己知道该怎么处理数据,所以我们只需要简单的利用stream.isWriting,就可以知道当前实例情况下要做什么。

如果我们期望写入数据,我们使用stream.SendNext()附加到数据流的IsFiring值,这是一个非常方便的方法,隐藏了数据序列化的所有辛苦工作。如果我们希望读数据,那就使用stream.ReceiveNext()。

Health 同步

好的,为了完成更新Player的功能,我们将同步Health值,以便Player的每个实例都有正确的Health值。这与我们刚刚介绍的IsFiring值使用完全相同的原则。

  1. 打开脚本PlayerManager

  2. 在IPunObservable.OnPhotonSerializeView中,SendNext和ReceiveNext处理IsFiring变量之后,同样的处理一下Health

     if (stream.isWriting)
     {
         // We own this player: send the others our data
         stream.SendNext(IsFiring);
         stream.SendNext(Health);
     }else{
         // Network player, receive data
         this.IsFiring = (bool)stream.ReceiveNext();
         this.Health = (float)stream.ReceiveNext();
     }
    
  3. 保存PlayerManager

这样就完成了同步Health变量。

原文

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容