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();
            }
            return _Instance;
        }
    }

 //锚点数据最小值的限制(为了定位更准确)
    private const uint minTrustworthySerializedAnchorDataSize = 500000;
    private string oldAnchorName = "AnchorName";
    public string AnchorName = "AnchorName";
    private string exportingAnchorName;

    private GameObject objectToAnchor;

    //要导出的锚点数据
    private List exportingAnchorBytes = new List();
    //要导入的锚点数据
    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();
            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();
        if (worldAnchor == null)
        {
            worldAnchor = objectToAnchor.AddComponent();
        }
        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


你可能感兴趣的:(Hololens开发)