基于XR Interaction ToolKit与PUN实现VR多人协同功能

        最近在整VR多人协同相关的开发工作,因为没怎么接触过多人开发这一块,碰到了不少坑,在这里总结一下个人的一些经验。

一.开发环境配置

       Unity版本:2019.3.4

       相关插件版本:

      Universal RP 7.1.8

      XR Interaction Tookit preview -0.9.4

      PUN2 2.22

    关于XR Interaction Tookit

      之前有做过相关的介绍与使用说明 参考这篇文章 基于XR Interaction ToolKit开发的VR双平台兼容项目(一) 这里就不过多说明了

    关于PUN2

        PUN(Photon Unity Networking)是unity上一款比较有名的多人交互的解决方案 网上有不少关于它的介绍与说明,这里也不再赘述了。不过有个可以优化一下PUN的网络的配置在这里要说明一下。因为PUN的服务器默认都是在海外的,国内用可能会有延时的情况出现。可以去Poton的中国官网申请免费的国内服务器,具体方法如下

1.进入官网(https://vibrantlink.com/

2.首页中找到“免费申请中国区光子云”

3.填写相关的资料并提交审核 ,这里需要注意的是需要把之前在官网创建的需要切到中国区的appid输入到申请表里面,并注意不要选择错类型。

4.一两个工作日后邮箱收到成功的邮件,就可以在Unity进行配置。

5.在unity中找到PUN的配置文件PhotonServerSettings,修改里面的Fixed Region为CN;找到脚本LoadBalancingClient.cs 把里面的NameServerHost属性修改成ns.photonengine.cn

配置好以上的选项后,测试了下网速基本是在50ms以下的延时。

二.开发的一些细节

1.模型的加载与同步

通过PUN提供的PhotonNetwork.Instantiate方法,可以把本地的模型创建并且同步到各自的客户端。但如果要下载服务器上的模型资源,并且同步到其他的用户的话还需要配合其他相关的方法来实现。

本人是通过Photon提供的组件同步的方法来实现类似的效果,具体实现如下:

a. 通过PhotonNetwork.Instantiate来创建一个空物体,并在上面挂载photonView组件,同时也挂上自定义的同步加载类ModelEntity,这个类要继承IPunObservable接口,并且实现OnPhotonSerializeView方法的话,就会自动被photonView检测到。

    ModelEntity的相关代码如下:

public class ModelEntity : MonoBehaviourPunCallbacks, IPunObservable
    {

        string id;
        int num;
        public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)
        {
            //拥有者 会把数据不断发送给其他人
            if (stream.IsWriting)
            {

                stream.SendNext(id);
                stream.SendNext(num);
            }
            else
            {

                // 其他用户 当拥有者发送数据会接收到数据
                id= (string)stream.ReceiveNext();
                num= (string)stream.ReceiveNext();


            }
        }

    }
}

b.在实例化这个同步的gameObject对象后,创建者把需要同步的id数据传进ModelEntity中,同时也要加载服务器的场景到本地;其他用户会通过Photon网络获取到创建的这个gameObject对象空物体,在检测到对应的id后,再通过网络加载对应id的模型到本地。这样就简单实现了同步加载服务器的模型的功能

2.对象的接管与操作

在应用中创建的同步对象,默认是只能创建者操作,如果其他用户想要接管这个对象并对它进行变换或者删除操作,需要获取到这个对象的操作权,具体操作如下:

a.将同步的对象挂载的photonView组件上的Ownership Transfer设置成 Takeover,表示这个对象是可以被接管的

b.通过代码获取到这个对象的photonView,设置gameObject.GetComponent<PhotonView>().TransferOwnership(PhotonNetwork.LocalPlayer),这个操作是强行把对象的一个控制权转交给本地的用户

c.如果需要同步物体的变换信息的话,可以在对象上挂在PhotonTransformView组件,根据需求勾选position,rotation和scale,这样的话本地用户不管是场景中直接拖拽或者是在代码中设置,都能过同步给其他网络用户

d.删除对象 通过PhotonNetwork.Destroy()可以把网络同步的对象销毁掉。

3.VR用户对象的创建

在多人VR中,并不需要为每个用户创建一个camera,因为我们只需要通过一个Camera组件看到世界物体,增加其他的用户Camera反而会出现报错 。如果真的需要同步其他的VR用户,只需通过PhotonNetwork.Instantiate创建一个玩家的对象模型,并且把本地的camera位置不断同步到这个对象模型上(VR中头像的位置就是camera的位置)

4.VR画线功能的实现

在多人互动中,如果需要通过把手柄当成“笔”来进行画线,并且同步到其他的用户,这就涉及了LineRenderer与同步的相关知识点。通过LineRenderer来记录手柄经过的每个途径点并且绘制成线,并且同步到其他用户的世界坐标中。在这里要注意的是,同步画线“点”的操作是在用户绘制完一条线之后,而不是边绘制边同步。因为不确定两边的网络情况延时怎样,如果是边画边同步途径点的话,在本地看起来是正常的,但其他网络用户里看到的东西基本是一塌糊涂。

同时也不建议每帧进行取点,不然对网络的负荷太大。而且也不建议每个位置都取点,而是判断点与点的距离大于某个阀值后再取点,这样也避免了大量点在同一个位置的情况。

5.用户离开房间的处理

当用户离开了房间或者由于异常断网,用户通过PhotonNetwork.Instantiate创建的对象并不会删除,而是默认转给了ClientMaster。如果用户创建过人物模型模型用来同步位置的话,这时就会遗留在场景里面。所以还需要对掉线的对象进行处理。 我的处理方法是创建出的用户虚拟形象里面添加一个用户离开房间的检测事件,当检测到用户是对应这个虚拟形象的模型时,就删除该对象,具体实现代码如下:

    public override void OnPlayerLeftRoom(Player otherPlayer)
    {
        if (owner == otherPlayer.NickName)
        {
            PhotonNetwork.Destroy(gameObject);
        }
    }

其中这个owner是在实例化这个对象时获取到的LocalPlayer.NickName。可能有人问为什么不直接用photonView.owner.NickName跟掉线的用户名进行判断,上面已经说过,当用户掉线时,模型就默认切换成ClientMaster,自然获取到的photonView.owner就不是对应掉线的用户了。

随便总结一下

因为是第一次接触多人交互编程这一块,很多东西都是瞎摸出来的,可能大多数并不是最优的方案,如果有错误的地方也希望有人能指正一下。同时也非常感谢【我是橙子a】这位博主的文章教程,真的学习了不少。

猜你喜欢

转载自blog.csdn.net/ssssssilver/article/details/109531179
今日推荐