Hololens 使用Unet共享詳細教程(五)

Hello World!我是山谷大叔~接下來我將出一系列Hololens開發教程(Hololens API解析空間共享、第三視角Spatial ViewMR交互設計視音頻通訊服務器開發,多人遊戲實戰……),感興趣的朋友可以關注我哦。下面開始放乾貨!

本節將是最後一節

我們將完成錨點數據的發送和接收。

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章