Hello World!我是山谷大叔~接下來我將出一系列Hololens開發教程(Hololens API解析、空間共享、第三視角Spatial
View,MR交互設計,視音頻通訊,服務器開發,多人遊戲實戰……),感興趣的朋友可以關注我哦。下面開始放乾貨!
本節將是最後一節
我們將完成錨點數據的發送和接收。
using UnityEngine;
using System.Collections.Generic;
using System;
using HoloToolkit.Examples.SharingWithUNET;
#if UNITY_EDITOR || UNITY_WSA
using UnityEngine.VR.WSA.Sharing;
using UnityEngine.VR.WSA;
using UnityEngine.VR.WSA.Persistence;
#endif
public class SharedCollectionAnchor : MonoBehaviour {
private static SharedCollectionAnchor _Instance;
public static SharedCollectionAnchor Instance
{
get
{
if (_Instance == null)
{
_Instance = FindObjectOfType<SharedCollectionAnchor>();
}
return _Instance;
}
}
//錨點數據最小值的限制(爲了定位更準確)
private const uint minTrustworthySerializedAnchorDataSize = 500000;
private string oldAnchorName = "AnchorName";
public string AnchorName = "AnchorName";
private string exportingAnchorName;
private GameObject objectToAnchor;
//要導出的錨點數據
private List<byte> exportingAnchorBytes = new List<byte>();
//要導入的錨點數據
private byte[] anchorData = null;
//用於發送錨點數據
private TransmitAnchorData networkTransmitter;
private bool createdAnchor = false;
//錨點導入
public bool ImportInProgress { get; private set; }
//錨點下載
public bool DownloadingAnchor { get; private set; }
//錨點建立
public bool AnchorEstablished { get; private set; }
//初始化條件檢測
private bool CheckConfiguration()
{
networkTransmitter = TransmitAnchorData.Instance;
if (networkTransmitter == null)
{
Debug.Log("No TransmitAnchorData found in scene");
return false;
}
if (SharedCollection.Instance == null)
{
Debug.Log("No SharedCollection found in scene");
return false;
}
else
{
objectToAnchor = SharedCollection.Instance.gameObject;
}
return true;
}
private void Start()
{
if (!CheckConfiguration())
{
Debug.Log("初始化失敗");
Destroy(this);
return;
}
//錨點數據讀取完成時調用 NetworkTransmitter_dataReadyEvent
networkTransmitter.dataReadyEvent += NetworkTransmitter_dataReadyEvent;
oldAnchorName = AnchorName = PlayerPrefs.GetString("AnchorSave");
//從商店讀取錨點
#if !UNITY_EDITOR && UNITY_WSA
AttachToCachedAnchor(AnchorName);
#endif
}
//錨點數據讀取完成
private void NetworkTransmitter_dataReadyEvent(byte[] data)
{
Debug.Log("Anchor data接收完成");
anchorData = data;
Debug.Log(data.Length);
DownloadingAnchor = false;
ImportInProgress = true;
Debug.Log("導入錨點數據");
WorldAnchorTransferBatch.ImportAsync(anchorData, ImportComplete);
}
//導入完成後,把錨點數據附加到 SharedCollection物體上
private void ImportComplete(SerializationCompletionReason status, WorldAnchorTransferBatch wat)
{
if (status == SerializationCompletionReason.Succeeded && wat.GetAllIds().Length > 0)
{
Debug.Log("導入完成!");
string first = wat.GetAllIds()[0];
Debug.Log("錨點名字: " + first);
WorldAnchor existingAnchor = objectToAnchor.GetComponent<WorldAnchor>();
if (existingAnchor != null)
{
//刪除久的錨點數據
DestroyImmediate(existingAnchor);
}
//綁定新的錨點數據
WorldAnchor anchor = wat.LockObject(first, objectToAnchor);
WorldAnchorHandle.Instance.AnchorStore.Save(first, anchor);
ImportInProgress = false;
AnchorEstablished = true;
Debug.Log("錨點建立完成!");
//存儲錨點名字
PlayerPrefs.SetString("AnchorSave", first);
}
else
{
Debug.Log("錨點導入失敗!");
}
}
//創建錨點數據,用於導入併發送
private void CreateAnchor(string name)
{
#if UNITY_EDITOR || UNITY_WSA
objectToAnchor = SharedCollection.Instance.gameObject;
WorldAnchorTransferBatch watb = new WorldAnchorTransferBatch();
WorldAnchor worldAnchor = objectToAnchor.GetComponent<WorldAnchor>();
if (worldAnchor == null)
{
worldAnchor = objectToAnchor.AddComponent<WorldAnchor>();
}
exportingAnchorName = name;
Debug.Log("導出錨點: " + name);
watb.AddWorldAnchor(exportingAnchorName, worldAnchor);
WorldAnchorTransferBatch.ExportAsync(watb, WriteBuffer, ExportComplete);
#endif
}
//存儲導出的錨點byte[]數據
private void WriteBuffer(byte[] data)
{
exportingAnchorBytes.AddRange(data);
}
//錨點數據導出完成時調用
private void ExportComplete(SerializationCompletionReason status)
{
if (status == SerializationCompletionReason.Succeeded && exportingAnchorBytes.Count > minTrustworthySerializedAnchorDataSize)
{
AnchorName = exportingAnchorName;
anchorData = exportingAnchorBytes.ToArray();
//把錨點數據出給 TransmitAnchorData
networkTransmitter.SetData(anchorData);
createdAnchor = true;
Debug.Log("錨點準備好了");
//存儲錨點名字,方便下次在同一空間啓動時直接導入,無需重新建立(有偏差時再創建)
PlayerPrefs.SetString("AnchorSave", name);
//開始發送錨點數據
networkTransmitter.ConfigureAsServer();
//通過Unet同步錨點名字
GameManager.Instance.CmdChangeAnchorName(name);
AnchorEstablished = true;
}
else
{
//如果序列化失敗或者數據小於最下限制,重新創建
CreateAnchor(exportingAnchorName);
}
}
//嘗試從商店中查找 anchorName 的錨點,如果有返回true,導入該錨點
private bool AttachToCachedAnchor(string AnchorName)
{
WorldAnchorStore anchorStore = WorldAnchorHandle.Instance.AnchorStore;
Debug.Log("查找錨點:" + AnchorName);
string[] ids = anchorStore.GetAllIds();
for (int index = 0; index < ids.Length; index++)
{
if (ids[index] == AnchorName)
{
Debug.Log("找到了商店中的錨點");
//導入商店中的 AnchorName 錨點
anchorStore.Load(ids[index], objectToAnchor);
AnchorEstablished = true;
return true;
}
}
Debug.Log("沒有在商店中找到錨點");
return false;
}
private void Update()
{
//錨點名字變化,等待新錨點數據(!createdAnchor 發送錨點數據的不需要更新了)
if (oldAnchorName != AnchorName && !createdAnchor)
{
Debug.Log("有新錨點數據");
oldAnchorName = AnchorName;
//如果商店中沒有該錨點,請求數據
if (!AttachToCachedAnchor(AnchorName))
{
Debug.Log("下載錨點數據...");
DownloadingAnchor = true;
//連接服務器,接收錨點數據
networkTransmitter.RequestAndGetData();
}
}
}
//創建SharedCollection的錨點,並同步
public void CreatNewSharedCollectionAnchor()
{
if (GlobleData.Instance.IsServer)
{
string name = Guid.NewGuid().ToString();
#if !UNITY_EDITOR && UNITY_WSA
CreateAnchor(name);
#endif
Debug.Log("服務器創建新錨點...");
}
else {
Debug.Log("非服務器無法創建新錨!");
}
}
}
如果有什麼疑問或者發現筆者的錯誤請留言!
下一節講解 相關的內容~~~
獲取源碼請在羣資料中下載
Hololens MR 技術交流羣 211031265