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