我们的程序VR 程序 需要 多人互联的功能,所谓需要什么我就去做什么原则,钻研了一个星期 终于算是把所需要的功能给实现了。(因为VR游戏不能像传统局域网游戏一样可以双开测试,所以每次测试都要把安装包发到另外一台电脑来测试,很是麻烦。而且因为是网络游戏,很容易出现host端正常运行,而服务器端出错的问题。所以我发了50次才实现了我们的需求。。心塞塞)

小技巧:开始测试时可以把发布设置中的支持VR关掉,使用屏幕控制方式来测试,这样会省很多时间,但是要是测试手柄功能的话,就没有办法啦。只能两台电脑测试。。或者你也可以自己写测试来测试手柄功能。

如果 你不太懂服务器 就像我一样,而且团队中没有专业的后台,但是你依然想做一个多人互联的VR 游戏,或许可以帮给你一个方向。

首先这个文章使用的网络组件是unity 自己的unet  说实话我觉得坑挺多的,用的比较多的photon也可以实现,但是这篇文章是针对unet的啦。

下载LRX.SteamVR.Network.Essentials工具包 这个在unity官方商店卖20刀,挺贵的,但是总有办法搞得到嘛。如果没有unet基础的我还是建议你先去看看unet的demo.这样学习这快一点。

demo研究透彻后,就可以根据自己的需求来改啦,他上面的手柄事件系统是自己写的,现在做VR程序的话都会用官方出的工具包吧,这里注意一定要在

void GetLeftControlEvent()
    {
        ///left menu
        leftcontrol = vrCameraRigInstance.transform.FindChild("Controller (left)");
        //must can find 
        m_LeftControlEvent = leftcontrol.GetComponent<VRTK_ControllerEvents>();

        if (m_LeftControlEvent == null)
        {
            Debug.LogError("can not find VRTK_ControllerEvents");
        }

        m_LeftControlEvent.ApplicationMenuPressed += new ControllerInteractionEventHandler(OnMenuClickDown);
    }



vrCameraRigInstance下引用,这是必须的,这样就可以不用他的啦。
其他都需要根据自己的需求来自己实现了,下面就提一些unet遇到的一些坑。
因为unet现在的资料还是很少,所以有很多很坑,下面这些都是我自己踩过的坑,真的很坑人。
一般游戏中 主角一般都是一个 也就是你加入网络控制器生成的那个物体,只有这个物体的islocalplayer 属性是真,而你要执行[command]的脚本的属性的<pre name="code" class="csharp">islocalplayer 必须为真.一般传统局域网游戏中这没有什么问题,但是在VR游戏中,你控制的是3个物体,一个头盔 两个手柄。手柄上的脚本如何执行<pre name="code" class="csharp">[command]呢。
<pre name="code" class="csharp">[Command]
    void CmdSpawnHands(NetworkInstanceId playerId)
    {
        // instantiate controllers
        // tell the server, to spawn two new networked controller model prefabs on all clients
        // give the local player authority over the newly created controller models
        leftHand = Instantiate(leftHandPrefab);
        rightHand = Instantiate(rightHandPrefab);


        var leftVRHand = leftHand.GetComponent<NetworkVRHands>();
        var rightVRHand = rightHand.GetComponent<NetworkVRHands>();

        leftVRHand.side = HandSide.Left;
        rightVRHand.side = HandSide.Right;
        leftVRHand.ownerId = playerId;
        rightVRHand.ownerId = playerId;

        NetworkServer.SpawnWithClientAuthority(leftHand, base.connectionToClient);
        NetworkServer.SpawnWithClientAuthority(rightHand, base.connectionToClient);
    }



就需要用到这个

<pre name="code" class="csharp"><pre name="code" class="csharp">NetworkServer.SpawnWithClientAuthority(leftHand, base.connectionToClient);函数,分发权利,这样lefthand,righthand才能执行<pre name="code" class="csharp">[command]的命令。其次,这里给权利的两只手 并不是手柄,可以是手柄的模型什么的,不能把手柄的prefab放到这里,因为使用官方工具包的话,手柄是强制作为头盔
的子物体的。而且因为这个函数生成的物体必须的<img src="" alt="" />设置为localplayerauthority。但是设置<pre name="code" class="csharp">localplayerauthority这个属性的物体必须是根节点,手柄不会作为根结点,这双重原因导致了必须用生成出来的手(模型)来绑定控制器。



<pre name="code" class="csharp">public static void AttachAtGrip(Transform holder, Transform objectToAttach, string gripName = "Grip")
    {
        var grip = objectToAttach.FindChild(gripName);
        objectToAttach.position = holder.position;
        objectToAttach.rotation = holder.rotation;
        objectToAttach.parent = holder;
        objectToAttach.localPosition = grip.transform.localPosition;
        objectToAttach.localRotation = grip.localRotation;
    }

这个代码是用来将生成出来的物体 和手柄控制器绑定的。很简单的绑定代码,

再说这个<pre name="code" class="csharp">[Command]要求真的是很苛刻。不光上述所说的条件,使用这个标签的方法一定要以cmd开头不说,参数还必须是数据类型的,不能传递组件类型的,什么game object神马的都不可以
这个真的坑了我很长时间,这个标签的意思就是在调用到这个函数时,是服务器来执行里面的方法。所以,不要在这个函数内找其他的物体,找不到的!这个可能你会看不明白
,但我也不清楚要怎么描述,一般也遇不到。既然是服务器执行,想要执行networkserver内的方法一定要在这个标签函数内。否则是不会执行的。
<pre name="code" class="csharp">[Command]函数一定要注意。我有很多次出错都是因为这个方法。