1. 程式人生 > 其它 >HTC_VR_Unity_Unet多人協同問題記錄以及解決

HTC_VR_Unity_Unet多人協同問題記錄以及解決

技術標籤:HTCUnet

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

}