前一段时间做一个了用于展示的多人的VR联机的简单的Demo,使用的是去年发售的HTC VIVE COSMOS ,走了许多弯路,浪费了许多时间,现在做完了写个东西记录一下。
首先了关于联机的工具的选择,最开始使用的是UNET,新版本的Unity好像不支持了,但是从Assess Store中可以导入mirror继续使用,但是使用UNET也找了很多教程,可以 传递手和头的position和rotation,头部的位置是可以正常获得的,但是手的位置会出现问题,具体就是一个房间中的两双手的position和rotation相同,会重叠在一切并且一起动,交互也会出现问题,小组的另一个大佬研究了好久也没有解决。最后在YouTube上发现了一个使用photon联机的教程,试了一下确实可以使用,于是最终使用了photon来进行联机。Steam VR 插件的版本是2.5.0,之前开发的项目使用了VRTK,但是旧版本的steamvr不支持cosmos,就放弃了vrtk,不过steamvr的基本功能已经满足了demo的要求了。
这篇文章主要介绍如何在加入房间后看见另外一个人的头和手以及两个人能够对同一物体进行交互。
1.导入steam vr plugin和photon
steamvr和photon的配置可以搜索到详细的资料,这里就不讲了。导入photon后可以注册账号免费使用photon的云服务器,当然也可以自己搭一个,用在局域网,不过免费的license需要联网验证。
2.加入服务器并生成手和头的模型
photon使用Instantiate生成的物体需要放在 Prefabs/Resource 文件夹下,之后首先要进行网络的连接,photon中有教程可以制作游玩大厅之类的,因为这个Demo比较简单就没有做,直接连入房间,当加入房间后会生成头和手的prefab,整个代码是根据photon自带的代码进行修改。
这个代码挂在场景中的物体中。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class NetManager : MonoBehaviour
{
//利用pothon新建场景并生成头部预制体
public GameObject headPrefab;
public GameObject leftHandPrefab;
public GameObject rightHandPrefab;
//public GameObject light1;
public void Start()
{
PhotonNetwork.ConnectUsingSettings( "1.0" );
}
// below, we implement some callbacks of PUN
// you can find PUN's callbacks in the class PunBehaviour or in enum PhotonNetworkingMessage
public virtual void OnConnectedToMaster()
{
Debug.Log("OnConnectedToMaster() was called by PUN. Now this client is connected and could join a room. Calling: PhotonNetwork.JoinRandomRoom();");
PhotonNetwork.JoinRandomRoom();
}
public virtual void OnJoinedLobby()
{
Debug.Log("OnJoinedLobby(). This client is connected and does get a room-list, which gets stored as PhotonNetwork.GetRoomList(). This script now calls: PhotonNetwork.JoinRandomRoom();");
PhotonNetwork.JoinRandomRoom();
}
public virtual void OnPhotonRandomJoinFailed()
{
Debug.Log("OnPhotonRandomJoinFailed() was called by PUN. No random room available, so we create one. Calling: PhotonNetwork.CreateRoom(null, new RoomOptions() {maxPlayers = 4}, null);");
PhotonNetwork.CreateRoom(null, new RoomOptions() { MaxPlayers = 4 }, null);
}
// the following methods are implemented to give you some context. re-implement them as needed.
public virtual void OnFailedToConnectToPhoton(DisconnectCause cause)
{
Debug.LogError("Cause: " + cause);
}
public void OnJoinedRoom()
{
Debug.Log("OnJoinedRoom() called by PUN. Now this client is in a room. From here on, your game would be running. For reference, all callbacks are listed in enum: PhotonNetworkingMessage");
//加入房间后生成头部预制体
PhotonNetwork.Instantiate(headPrefab.name, ViveManager.Instance.head.transform.position, ViveManager.Instance.head.transform.rotation,0);
PhotonNetwork.Instantiate(leftHandPrefab.name, ViveManager.Instance.leftHand.transform.position, ViveManager.Instance.leftHand.transform.rotation, 0);
PhotonNetwork.Instantiate(rightHandPrefab.name, ViveManager.Instance.rightHand.transform.position, ViveManager.Instance.rightHand.transform.rotation, 0);
// PhotonNetwork.Instantiate(light1.name, new Vector3(0, 1, 1), Quaternion.Euler(45f, 0.1f, 0.1f), 0);
}
}
3.同步手和头的位置信息
在头和手的prefab中挂载photon view 和photon transform view ,勾选photon transform view中的前两个同步position和rotation的选项,之后把photon transform view 拖到 photon view中的最下面的observed components 列表中,这样如果物体的position和rotation发生变化就会在所有的用户中都发生改变。
之后新建脚本用于同步头和手的位置,思路就是先检查是不是自己的头和手,是的话就使生成的头和手的位置和steamvr中获取的位置相同,不过有个问题是生成的手的位置和实际位置有点偏差,而且使用steamvr中的player 的prefab会同时有新生成的和steamvr生成的两双手,可以写代码检测如果是本地的手就关掉mesh renderer 。代码如下,挂在头和手的prefab上,头是1,左手是2,右手是3.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CopyScript : Photon.MonoBehaviour
{
public int index = 1;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
if (photonView.isMine)//如果物体是本地的就更新位置信息
{
switch (index)
{
case 1: //head
transform.position = ViveManager.Instance.head.transform.position;
transform.rotation = ViveManager.Instance.head.transform.rotation;
break;
case 2: //lefthand
transform.position = ViveManager.Instance.leftHand.transform.position;
transform.rotation = ViveManager.Instance.leftHand.transform.rotation;
// this.GetComponent<MeshRenderer>().enabled = false;
// this.gameObject.SetActive(false);
this.transform.GetComponentInChildren<SkinnedMeshRenderer>().enabled = false;
break;
case 3: //righthand
transform.position = ViveManager.Instance.rightHand.transform.position;
transform.rotation = ViveManager.Instance.rightHand.transform.rotation;
//this.GetComponent<MeshRenderer>().enabled = false;
this.transform.GetComponentInChildren<SkinnedMeshRenderer>().enabled = false;
// this.gameObject.SetActive(false);
break;
}
}
}
}
这样联机的两个玩家就能各种看到对方的手和头的模型来。
有时间再接着写