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