王者荣耀实时对战服务器Photon之PUN修改网络角色预制

发表于2017-11-19
评论0 1.3w浏览

本节将指导您修改“角色”预制,完成角色预设在pun中的功能实现。 我们在前面已经创建了一个场景中使用的角色,但是现在我们要修改它,以便在PUN环境中使用它时,它的工作原理和顺序。 这些修改的地方不是很多但是还是至关重要的对了解和深入了解pun的网络概念和基础的应用

PhotonView Component

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

添加一个PhotonView组件到我的机器人角色预设。

我们来设置一下我们要观察的内容,然后我们回到这个PhotonView Component并完成它的设置。

Transform Synchronization

我们想要同步是角色的位置和旋转,以便当玩家移动时,其他计算机上的其他玩家也可以看到相同的移动和旋转。

您可以直接在自己的脚本中观察Transform组件,但由于网络延迟和数据同步的问题,您将遇到很多麻烦。幸运的是,为了简化这个常见任务,我们将使用[Photon Transform View]组件,作为Transform组件和PhotonView之间的“中间人”。 基本上,你可以使用这个组件来解决同步问题。

1.将PhotonTransformView”添加到“机器人角色”预制上,

2.将PhotonTransformView从其标题拖到PhotonView组件中的第一个Observable组件条目上


3.现在,检查PhotonTransformView中的同步位置

4.在同步位置中,选择“内插值的Lerp值”

5.将Lerp Speed”设置为10(越快速度越快)

6.检查SynchronizeRotation

提示:注意子部分中的说明帮助书帮助链接。 点击它来显示信息,并了解所有各种设置及其效果


Animator Synchronization

PhotonAnimatorView组件使网络设置变得轻而易举,节省了大量的时间和麻烦。它允许您定义要同步的层次权重和哪些参数。层次权重只有在游戏中改变时才需要进行同步,并且根本不需要同步它们就可以避免。参数也是如此。有时可以从其他因素导出动画的价值观。需要同步的参数尽可能的少。

1.将PhotonAnimatorView添加到机器人Kyle Prefab

2.将PhotonAnimatorView从其标题拖到PhotonView组件的新的Observable组件条目中

3.现在,在“同步参数”中,将“速度”设置为“离散”

4.将方向设置为离散

5.设置跳转到离散

6.将您设为禁用


每个值可以被禁用,或者是离散地或连续地同步。 在我们的例子中,由于我们没有使用Hi参数,所以我们将禁用它并从带宽中保存。

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

连续同步意味着PhotonAnimatorView运行每一帧都进行计算进行同步。 当OnPhotonSerializeView被调用(每秒10次)时,自上一次调用以来记录的值一起发送。 接收客户端然后按顺序应用值以保持平滑过渡。 当这种模式更平滑时,它也会发送更多的数据来达到这个效果。

User Input Management

网络用户控制的一个重要方面是,所有角色都将实例化相同的预制,但只有一个表示用户实际在电脑前播放,所有其他实例表示其他用户在其他计算机上播放。 所以这个想法的第一个障碍就是“输入管理”。 我们如何在一个实例而不是其他实例上启用输入,以及如何知道哪一个是正确的? 输入isMine概念。

1.我们来编辑我们之前创建的PlayerAnimatorManager脚本。

2.打开脚本PlayerAnimatorManager

3.将PlayerAnimatorManager类从MonoBehaviour转换为Photon.MonoBehaviour,它方便地显示了photonView组件。

4.在Update()调用中,插入一开始

if (photonView.isMine == false && PhotonNetwork.connected == true)

    return;

5.保存脚本PlayerAnimatorManager

好的,如果实例由'client'应用程序控制,PhotonView.isMine将是真的,这意味着这个实例代表在这个应用程序中在这台计算机上的物理人物。 所以如果它是假的,我们不想做任何事情,完全依靠PhotonView组件来同步我们之前设置的变换和动画组件。

为什么要在我们的if语句中强制PhotonNetwork.connected == true因为在开发过程中,我们可能想要测试这个预制而不连接。 例如,在虚拟场景中,只需创建和验证与网络功能无关的代码。 所以使用这个附加表达式,如果我们没有连接,我们将允许使用输入。 这是一个非常简单的方法,将在开发过程中大大提高您的工作效率。

Camera Control

与输入一样,角色只有一个游戏的视图,所以我们需要CameraWork脚本只跟随本地控制的角色,而不是其他角色。 这就是为什么CameraWork脚本需要这样的能力来定义何时跟随。

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

2.打开PlayerManager脚本。

3.在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);

    }

4.保存脚本PlayerManager

首先,它获取CameraWork组件,我们希望这样,所以如果我们没有找到它,我们输出一个错误。 那么,如果photonView.isMine是真的,这意味着我们需要初始化这个实例,所以我们调用_cameraWork.OnStartFollowing(),这有效地使相机跟随场景中的实例。所有其他角色实例将其photonView.isMine设置为false,因此它们各自的_cameraWork将不会执行任何操作。

最后一个改变,使这项工作:

在角色预制上,关闭CameraWork组件上的启动

它现在有效地将逻辑追随到玩家脚本PlayerManager中,该脚本将如上所述调用_cameraWork.OnStartFollowing()。

Beams Fire Control

射击也遵循上面的输入控制原理.

打开脚本PlayerManager

if语句判断输入处理调用。

if (photonView.isMine) 

    ProcessInputs ();

但是,当测试这个,我们只看到本地玩家的射击。 我们需要看看其他实例是否触发! 我们需要一种在网络上同步启动的机制。 为了做到这一点,我们将手动同步IsFiring布尔值,到目前为止,我们已经离开了PhotonTransformViewPhotonAnimatorView来为我们做所有的变量内部同步。

打开脚本PlayerManager

实现IPunObservable

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();

保存脚本PlayerManager

返回Unity编辑器,在您的资产中选择我的机器人预制,并在PhotonView组件中添加一个观察条目,并将PlayerManager组件拖动到它


没有最后一步,IPunObservable.OnPhotonSerializeView从来没有被调用,因为它没有被PhotonView观察到。

在这个IPunObservable.OnPhotonSerializeView方法中,我们传递一个变量流,这是通过网络发送的,如果我们有机会读取和写入数据,这个调用。 当我们是localPlayerPhotonView.isMine == true)时,我们只能写,否则我们读。

由于流类有帮助我们告诉该怎么做,我们只需依靠stream.isWriting知道当前实例中的预期内容。

如果我们预期写数据,我们将使用Stream.SendNext()附加到数据流的IsFiring值,这是一种非常方便的方法,它将所有的数据序列化工作全部放弃。 如果我们预期读取,我们使用stream.ReceiveNext()。

Health Synchronization

好的,要完成更新网络的角色功能,我们将同步健康值,以便角色的每个实例具有正确的健康值。 这与上面我们刚才介绍的IsFiring值完全一样。

打开脚本PlayerManager

SendNextReceiveNextIsFiring变量之后,在IPunObservable.OnPhotonSerializeView中,对于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();

保存脚本PlayerManager

在这种情况下,需要同步Health变量。


不管你有关于Photon产品的问题或者是Photon价格问题或者Photon教程方面的问题或者其他问题都可以联系我们给我我们留言,我们真诚的为您服务。

关注我们公众号PhotonServer 获取最新教程资源。


王者荣耀实时对战服务器Photon之Pun应用系列文章 如果你喜欢请关注我公众号,并推荐给你你的小伙伴,谢谢。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引