从业务发展来看,您可能会对 Unity 感到有点震惊。传统上,游戏开发人员更注重让外部比内部更漂亮。像依赖注入之类的东西对于游戏开发来说是闻所未闻的或被认为”太重”的。但是,如果您仍在开发过程中,实际上能够访问一致的(模拟)数据服务,而不是真正的实时数据服务可能是一个很大的优势,尤其是当该数据服务是速率有限或昂贵的。
您可能还喜欢:
迁移到 MRTK2:与空间地图交互
混合现实工具包2 提供了一个伟大的功能:扩展服务。它实际上非常容易使用,我将展示一个简单的示例。我几乎一年前在非常早期的alpha阶段就写过这个,但现在它实际上已经可用了。
设置舞台
使用 Unity 2018.4.6f1,我创建了一个简单的项目 MKRT2 DepInject 使用 3D 模板,导入了 MRKT2 和 TextMeshPro。对于后者,我通常只获取必要的资源。然后,I 并将 MRKT2 添加到项目中的样本场景中。对于默认配置文件,我通常采用默认霍洛伦斯2配置文件。此外,不要忘记将平台设置为 UWP(文件/生成设置)
此外,从Unity 商店导入JSON.net非常重要。
扩展服务
服务需要接口、实现类、可选检查器、配置文件和默认配置文件资产。现在,后三个听起来可能有点抽象,但实际上可以归结为:
- 检查器可用于在编辑器中显示服务的运行时状态。它基本上是一个调试工具。它完全是可选的,在大多数情况下,它没有必要。
- 配置文件是保存类配置信息的类。如果您已经使用 MRKT2 一段时间了,则一直都在使用它们 – 克隆配置文件和更改设置。
- 默认服务配置文件资产基本上是配置文件类的序列化版本。
这似乎是一个很多的工作,但实际上有一个不错的工具来生成样板的所有 – 虽然必须得到一些拉请求自己,使其工作,因为我以为是。
创建扩展服务
选择混合现实工具包/实用程序/创建扩展服务。这将启动此 UI:
命名服务”数据服务”。您会注意到”服务”后缀是强制性的。为命名空间选择”服务”。然后单击”下一步”按钮。这将显示下一阶段。
现在我喜欢整理我的东西一点点,所以我倾向于把东西在文件夹中。脚本位于脚本/服务文件夹中,配置文件中的配置文件。您可以通过从资源中拖动文件夹来设置此设置cheeli.com.cn/wp-内容/上传/2019/11/setoptions-1.png”/*
点击下一个,在下一个屏幕上,单击”不立即”,否则,您将编辑默认配置文件。实际上,您正在修改 MRKT2 的默认设置。 只有在克隆了正确的配置文件后,才能执行此操作。
您还将注意到,虽然指定了默认资产应该已在配置文件文件夹中创建,但实际上它是在服务文件夹中创建的。看,我需要提出另一个拉请求。不管怎样我移动到 DefaultDataServiceProfile
配置文件,让它坐在那里
注册服务
首先,我们克隆了顶级配置文件。
然后,我们禁用探查器,因为这是恼人的方式,你想演示的东西:
然后,我们选择”扩展”选项卡,并将”默认混合现实注册服务提供商配置文件”(MRTK2 的创建者似乎喜欢相当冗长的名称,您可能已经注意到)到 MyMixedRealityRegisteredServiceProvidersProfile
:
现在,您可以实际单击”注册新的服务提供商”按钮并注册服务:
然后,您必须单击配置配置文件下拉列表,该列表不幸地显示所有可能的配置文件,并且您必须选择所需的配置文件, DefaultDataServiceProfile
这是,幸运的是,它位于列表的顶部:
最终结果应如下所示:
现在,配置工作终于完成了,我们将添加一些代码。
数据和数据集
我的简单示例将从 Web 读取 JSON 文件并显示文本中的内容。因此,我们需要一个数据文件和一个类来反序列化它。
数据文件位于此处,可以反序列化的类如下所示:
using Newtonsoft.Json;
namespace Json
{
public class DemoData
{
[JsonProperty("firstName")]
public string FirstName { get; set; }
[JsonProperty("lastName")]
public string LastName { get; set; }
}
}
配置配置文件
因此,要使配置配置文件实际可配置, DataServiceProfile
需要更改类。实际上,我们需要创建一个属性来存储 URL。因此,我们添加一个可序列化字段和一个只读属性。喜欢这个:
using System;
using UnityEngine;
using Microsoft.MixedReality.Toolkit;
namespace Services
{
[MixedRealityServiceProfile(typeof(IDataService))]
[CreateAssetMenu(fileName = "DataServiceProfile",
menuName = "MixedRealityToolkit/DataService Configuration Profile")]
public class DataServiceProfile : BaseMixedRealityProfile
{
[SerializeField] private string _dataUrl; public string DataUrl => _dataUrl; } }
以红色/粗体添加代码
因此,让我们将默认配置文件克隆到 SchaikwebProfile
:
并输入数据Url:https://www.schaikweb.net/demo/DemoData.json。结果:
现在,您已经可以看到如何快速从一个配置配置文件更改为另一个配置配置文件。实际上,您可以将 schaikweb 配置文件克隆到另一个具有不同设置的配置文件。现在,它只有一个属性,但它可以有很多 – 并且你可以通过选择一个新的配置文件从一个设置更改为另一个。
实施实际服务
服务生成的代码 (有点缩写 ) 如下所示:
namespace Services
{
[MixedRealityExtensionService(....
public class DataService : BaseExtensionService, IDataService,
IMixedRealityExtensionService
{
private DataServiceProfile dataServiceProfile;
public DataService(IMixedRealityServiceRegistrar registrar, ....)
{
dataServiceProfile = (DataServiceProfile)profile;
}
public override void Initialize()
{
// Do service initialization here.
}
public override void Update()
{
// Do service updates here.
}
}
}
您可以看到配置文件 (保存设置的类 ) 正在馈入构造函数中。现在,我们不需要在此简单服务中初始化和更新,因此我们删除它并添加此项:
public async Task<IList<DemoData>> GetNames()
{
using (var request = new HttpRequestMessage(HttpMethod.Post,
dataServiceProfile.DataUrl))
{
using (var client = new HttpClient())
{
var response = await client.SendAsync(request);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<IList<DemoData>>(result);
}
}
}
请注意从 dataserviceProfile
!
当然,我们还需要将此方法添加到 IDataService
接口中:
public interface IDataService : IMixedRealityExtensionService
{
Task<IList<DemoData>> GetNames();
}
现在一些行动…
因此,我创建了这个 MonoBehaviour
小,实际访问和使用服务。
public class NamesReader : MonoBehaviour
{
[SerializeField]
private TextMeshPro _text;
private IDataService _dataService;
void Start()
{
_dataService = MixedRealityToolkit.Instance.GetService<IDataService>();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Alpha3))
{
LoadNames();
}
if (Input.GetKeyDown(KeyCode.Alpha4))
{
_text.text = "";
}
}
private async Task LoadNames()
{
var names = await _dataService.GetNames();
_text.text = string.Join(Environment.NewLine,
names.Select(p => $"{p.FirstName} {p.LastName}"));
}
}
您可以看到它是如何简单地获取对 start 方法中的服务的引用。如果在编辑器中运行此选项并按”3″,它将尝试从服务加载值,并将它们显示为 TextMeshPro _text(按”4″将再次清除它)cheeli.com.cn/wp-内容/上传/2019/11/服务结果-1.png”/*
基本上,从我的网站上的数据文件直接转储:
[
{
"firstName": "Scott",
"lastName": "Guthrie"
},
{
"firstName": "Alex",
"lastName": "Kipman"
},
{
"firstName": "Scott",
"lastName": "Hanselman"
}
]
模拟服务访问
现在,让我们假设,目前,此数据服务是非常昂贵、缓慢或访问受限的。或者,您需要测试某些边缘情况,但数据服务并不总是在需要时提供它们。换句话说,你想做一个假服务-模拟服务。现在,这很简单。
因此,让我们构建一个模拟服务:
[MixedRealityExtensionService(....
public class MockDataService : BaseExtensionService,
IDataService
{
public MockDataService(IMixedRealityServiceRegistrar registrar, ....
{
}
public async Task<IList<DemoData>> GetNames()
{
var data = new List<DemoData>
{
new DemoData {FirstName = "Joost", LastName = "van Schaik"},
new DemoData {FirstName = "John", LastName = "Doe"},
new DemoData {FirstName = "Kermit", LastName = "the Frog"},
};
await Task.Yield();
return data;
}
}
因此,我们实现相同的接口,但它不采用 DataServiceProfile
配置(尽管如果我实现了构造函数,它完全可以)。现在,服务的第二个实现版本出现在下拉列表中:
现在,您可以快速将单个服务从生产实现更改为测试实现。模拟服务将显示:
但更酷的是,当您从配置文件创建”模拟 RegisteredServiceProfile
配置文件”。如果你有20个服务(相信我,服务的数量上升相当快),你可以改变从测试到生产,只需切换配置文件。因此,我克隆 MyMixedRealityRegisteredServiceProvidersProfile
到 MockMixedRealityRegisteredServiceProvidersProfile
本身,现在,只需切换配置文件,只需一个简单的下拉列表即可更改整个扩展服务定义。
结论
扩展服务是 MRTK2 的一项非常强大的功能,可用于数据服务的集中访问 – 通常,在您旧 HoloToolkit 中,您会使用 Singletons。但是,使用服务配置文件也提供了一种在实际实现和模拟实现之间切换的快速简便方法,将企业级开发的重要组成部分带入了传统的 – ahem — 更混乱的 Unity 开发环境。
演示项目可在此处找到。