HTC_VR_Unity_Unet多人协同
因为要做HTC协同的项目,一开始选定了使用UNET完成协同部分操作,后来Unet碰到了很多坑,在这里记一下:
解决了场景跳转报错问题
解决了多个HTC预制冲突问题
///网络管理脚本
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
///
/// 将NetworkManager方法按这里的方式重写
/// 因为我只用到了这些方法所以只重写这一小部分
/// 如果用到其他也需要重写不然会遇到未知的错误
/// 具体原因不清楚
///
public class VR_NetWorkeManager : NetworkManager
{
public Transform thePlayersParent;
public override void OnServerAddPlayer(NetworkConnection conn, short playerControllerId)
{
// base.OnServerAddPlayer(conn, playerControllerId);
var player = (GameObject)GameObject.Instantiate(playerPrefab, startPositions[0].position, Quaternion.identity);
player.transform.parent = thePlayersParent;
NetworkServer.AddPlayerForConnection(conn, player, playerControllerId);
//NetworkServer.SendByChannelToAll();
}
public override void OnClientSceneChanged(NetworkConnection conn)
{
Debug.Log(456);
ClientScene.AddPlayer(conn, 0);
//base.OnClientSceneChanged(conn);
//ClientScene.Ready(conn);
}
public override void OnClientConnect(NetworkConnection conn)
{
base.OnClientConnect(conn);
}
public override void OnServerSceneChanged(string sceneName)
{
Debug.Log(sceneName);
//base.OnServerSceneChanged(sceneName);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Networking;
using Valve.VR;
using Assets.Scripts.VR_GameTools;
using Valve.VR.InteractionSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
using UnityEngine.Video;
using DG.Tweening;
///
/// 必须挂在NetWorkeManager生成的Play上
/// 需要将HTC预制体的左手和右手改名成Hand1和Hand2
/// 需要一个VR_RayPrefab射线的预制体,最好挂上网络标识NetWorkeIdentity
/// 需要给VR_CaiDan,VR_Tra赋值VR_Hand_Axis暂时没用上
///
public class VR_MyPlayer : NetworkBehaviour
{
#region 头盔相关参数
//头盔相关参数==
GameObject VR_Hand1;//手柄1
GameObject VR_Hand2;//手柄2
public SteamVR_Input_Sources VR_LeftHand;
public SteamVR_Input_Sources VR_RightHand;
public SteamVR_Action_Boolean VR_CaiDan;
public SteamVR_Action_Boolean VR_Tra;
public SteamVR_Action_Vector2 VR_Hand_Axis;
public GameObject VR_RayPrefab;
#endregion
#region 网络物体
#endregion
#region 本地客户端获取的物体
#endregion
#region 生命周期
void Start()
{
if (!isLocalPlayer)
{
//不是本地客户端执行什么
//这里在跳转场景时会碰到问题
//原因是有多个客户端的预制体
//各客户端相机显示的是同一个相机,HTC位置链接的是所有预制体所以在这里会出现问题
//解决办法:在不是本地客户端的是隐藏除了要显示的身体模型外的所有组件
//如果需要同步手柄位置,人物动作,可以再写一个没有相机,以及HTC同步的位置的模型,用网络连接的方式同步,PS这里没写所以没有相关代码
return;
}
//本地客户端执行什么
}
void Update()
{
if (!isLocalPlayer)
{
return;
}
#region hand1扳机事件
VR_Hand1 = GameTools.FindChild(transform, "Hand1").gameObject;
if (VR_Tra.GetStateDown(VR_LeftHand))
{
Ray ray1 = new Ray(VR_Hand1.transform.position, VR_Hand1.transform.forward);
RaycastHit hitinfo;
if (Physics.Raycast(ray1, out hitinfo))
{
}
}
if (VR_Tra.GetState(VR_LeftHand))
{
Ray ray1 = new Ray(VR_Hand1.transform.position, VR_Hand1.transform.forward);
RaycastHit hitinfo;
if (Physics.Raycast(ray1, out hitinfo))
{
}
}
if (VR_Tra.GetStateUp(VR_LeftHand))
{
MovePlayerId = int.Parse((GetComponent<NetworkIdentity>().netId.ToString()));
Ray ray1 = new Ray(VR_Hand1.transform.position, VR_Hand1.transform.forward);
RaycastHit hitinfo;
if (Physics.Raycast(ray1, out hitinfo))
{
// 点击执行的方法
TriggerEvent(hitinfo.transform.name,hitinfo.transform.gameObject);
}
}
#endregion
#region 扳机2事件
VR_Hand2 = GameTools.FindChild(transform, "Hand2").gameObject;
//Debug.DrawRay(ray.origin, ray.direction, Color.red);
if (VR_Tra.GetStateDown(VR_RightHand))
{
Ray ray1 = new Ray(VR_Hand2.transform.position, VR_Hand2.transform.forward);
RaycastHit hitinfo;
if (Physics.Raycast(ray1, out hitinfo))
{
}
}
if (VR_Tra.GetState(VR_RightHand))
{
Ray ray1 = new Ray(VR_Hand2.transform.position, VR_Hand2.transform.forward);
RaycastHit hitinfo;
if (Physics.Raycast(ray1, out hitinfo))
{
}
}
if (VR_Tra.GetStateUp(VR_RightHand))
{
MovePlayerId = int.Parse((GetComponent<NetworkIdentity>().netId.ToString()));
Debug.Log("手柄2名称:" + VR_Hand2.gameObject.name);
Ray ray = new Ray(VR_Hand2.transform.position, VR_Hand2.transform.forward);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{ // 点击执行的方法
Debug.Log("手柄2名称:" + VR_Hand2.gameObject.name);
TriggerEvent(hit.transform.name,hit.transform.gameObject);
}
}
#endregion
///点击菜单跳转场景
if (VR_CaiDan.GetStateDown(VR_LeftHand)|| VR_CaiDan.GetStateDown(VR_RightHand))
{
//name要跳转的场景
CmdLoadSceneAsync(name);
}
}
#endregion
#region 本地方法
/// <summary>
/// 画一条射线
/// </summary>
/// <param name="hand22"></param>
void CreatRay(GameObject hand22)
{
Vector3 pos = new Vector3(0.002f, -0.004f, 1.001f);
Vector3 scale = new Vector3(0.001f, 0.001f, 100.0f);
Vector3 rot = new Vector3(0, 0, 0);
GameObject _Ray = Instantiate(VR_RayPrefab) as GameObject;
_Ray.transform.SetParent(hand22.transform);
_Ray.transform.localScale = new Vector3(0.002f, 0.002f, 100f);
_Ray.transform.localPosition = Vector3.zero + new Vector3(0f, 0f, 50f);
_Ray.transform.localRotation = Quaternion.identity;
//NetworkServer.Spawn(_Ray);
}
/// <summary>
/// 手柄点击触发方法
/// 根据名字判断执行什么方法
/// </summary>
/// <param name="name">名字</param>
/// <param name="hit">碰撞点</param>
void TriggerEvent(string name,GameObject hit)
{
Debug.Log("手柄2名称:" + name);
switch (name)
{
case "Magnify":
CmdScale(0.1f);
break;
}
}
#endregion
#region
/// <summary>
/// 这里是客户端发给服务器
/// </summary>
/// <param name="dam">传输的数值,支持float,int ,string,Vector3等数值但是不支持GameObject等类型</param>
[Command]
void CmdScale(float dam)
{
RpcScale(dam);
}
///
/// 点击后触发什么功能写在RPC里面
/// 这里是服务器分发给客户端执行
///
/// 传输的数值,支持float,int ,string,Vector3等数值但是不支持GameObject等类型
[ClientRpc]
void RpcScale(float dam)
{
}
#endregion
}