使用UWP开发HoloLens的简介(译文)
By S.F.
本文链接 https://www.kyfws.com/news/introduction-to-hololens-development-with-uwp/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 29 分钟阅读 - 14163 个词 阅读量 0使用UWP开发HoloLens的简介(译文)
原文地址:https://www.codeproject.com/Articles/1107169/Introduction-to-HoloLens-Development-with-UWP
原文作者:Joel Ivory Johnson
译文由本站翻译
前言
在本文中,我将介绍如何为HoloLens开发设置系统,应用程序与其他UWP平台的兼容性,并介绍用于制作3D应用程序的Unity.
介绍
如果您像我一样,那么您还没有机会购买自己的HoloLen.在撰写本文时,我目前正处于第5轮邀请中购买HoloLens.虽然我自己没有耳机,但是Razorfish的Emerging Experiences团队为我带来了享受优质时光的好处与单位之一.相对于代码而言,这篇文章将是轻而易举的,不过还是一个介绍. HoloLens是一种新的体验,与其他Windows 10设备不太一样,这种新体验值得关注.在本文中,我仅尝试将几个Hello World类型的应用程序部署到HoloLens,并尽可能将相同的程序部署到其他设备.
它是什么?
微软对HoloLens的描述之一是" Windows 10是第一个使用API来支持全息计算的平台,这些API能够在不受限制的设备上注视,手势,语音和环境.“另一个是” Microsoft HoloLens是第一台完全不受限制的全息计算机,使您可以与世界上的高清全息图进行交互.“我感到不得不在这里对词的使用发表评论.有时将关于单词用法的观点分为说明性观点和描述性观点.规定性观点是,必须以特定的方式使用词语,而不一致的用法是错误的.描述性观点是,单词意味着人们想要表达的含义.只要演讲者和听众就预期的用法达成一致,那么一切就正确了.我不会轻易掉入一个或另一个,因为我可能会根据上下文切换.我倾向于用"全息图"一词来说明性的观点.通过全息透镜看到的不是全息术中所用单词的全息图.还没有(尚未)通过光场重建图像.尽管HoloLens与全息术没有任何关系,但仍有一些论据可以证明此处使用该术语的合理性.我在最近写的东西中提到了合理性.话虽如此,我不会再提出反对使用世界"全息图"的任何论点,而将采用描述性观点,以便能够与其他人就HoloLens进行交流.对于那些对语言有描述性看法的人,请查看Ammon Shea撰写的” Bad English"一书.这是许多书中的一本,讲述了一旦被发现令人反感的单词用法现在已成为日常语言的一部分. 笼统地说,HoloLens是混合现实或增强现实平台.它能够将应用程序窗口或3d对象覆盖在真实世界的视野内.这与虚拟现实(VR)的不同之处在于,VR阻碍了人们对现实世界的看法. HoloLens还是基于Windows 10的平台.针对Windows 10的通用Windows平台(UWP)的应用程序通常不仅可以在HoloLens上运行,而且还可以在Windows 10台式机/笔记本电脑,Windows 10 Mobile,Xbox One或受支持的IoT平台(如Raspberry Pi)上运行.到目前为止,没有星号或两个附加的互操作性还不存在.有些功能在某些平台上尚不可用.例如,Xbox One开发人员预览版支持基于HTTP/WebSocket的网络调用,但不支持TCP/UDP调用.与SMS相关的呼叫在没有SMS功能的平台上将无法使用.这些设备倾向于具有不同的主要交互模式.语音,游戏控制器,触摸键盘,物理键盘以及手势和注视.由于这些设备在许多设备类型上都是可选的,因此我无法对哪些设备具有哪种交互形式做出有意义的说明.一台计算机可能会或可能不会附带键盘. HoloLens支持蓝牙上的键盘和鼠标,但我一般不会期望将其连接到设备上. Microsoft已经做了一些工作来抽象出这些设备类型之间的某些差异.但是它们是需要注意的差异.
关于互动
作为Windows 10设备,HoloLens让我想起了更多来自Mobile Windows设备(例如Windows RT平板电脑或手机)的体验.在发布时,一次仅允许一个应用程序处于活动状态.尽管随着2016年5月更新,可能有多达3个应用程序处于活动状态.它也是单用户设备.一次只能使用一个真实帐户.更改设备使用的真实帐户是通过擦除其内存来完成的. HoloLens上的用户输入通常通过手势,注视元素和语音输入来完成.第一次使用HoloLens时,我没有充分利用语音输入.可以通过查看虚拟键盘上的各个键并选择它们来输入文本.一种狩猎和啄食的形式,对于大量文本输入而言可能有点疲劳.但是不必那样输入文本.听写要好得多.可以通过转动头部使其视线居中并在空中轻拍手势来选择元素. HoloLens附带了一个附件,该附件具有一个可以单击的按钮,而无需使用空中点击手势.在允许滚动的元素上
设置开发环境
为了在HoloLens上进行开发,您需要一台运行Windows 10和Visual Studio Update 2的计算机.您将要安装启用HoloLens的Unity版本(在撰写本文时为beta版)和HoloLens SDK.进行HoloLens开发的计算机的内存要求将取决于您是否具有物理硬件.有了物理硬件,我在拥有8 GB内存的计算机上表现还不错.当尝试使用模拟器时,仅8个演出还不够. 12场演出很好.我建议至少使用16.如果您使用的是模拟器,则还需要使用Windows 10的专业版或企业版.否则,您将无法使用该模拟器.在开发基于2D XAML的应用程序时,您可以在本地计算机上对其进行测试,而无需进行仿真.如果您想进行身临其境的体验(Microsoft称其为具有"体积视图"的"全息应用程序"),则需要使用仿真器或Hololens
从平常出发
如果您已经开发了Windows平台,但是还没有在Windows Store Apps(WinRT或Windows 10 Universal)上进行过多开发,则有一些方法可以在非WSA上执行任务,而这些方法在WSA中不太适合.在WSA之前,可能长时间运行的调用(如果不允许阻塞UI线程,则任何调用都会使UI显得响应性较差),即使这不是最好的主意,仍可以在UI线程上对其进行调用.对于希望他们的应用程序具有更快响应能力的开发人员,可以使用异步调用.通常长时间运行的呼叫处理文件或网络呼叫.在WSA之前,异步处理其中一些呼叫是可选的. WSA将强制实施更快速的响应.除了写入设备文件外,默认情况下没有足够的位置来阻止WSA之前的应用程序写入人的文件系统上的任意位置.系统上的文件许可权将阻止对某些位置的读取或写入成功,但是在API级别上没有任何东西可以阻止这种尝试. WSA改变了这种情况.应用程序具有自己的隔离存储(此概念曾存在过,但开发人员可以选择不使用它).应用程序无权访问彼此的应用程序存储.还有一些通用区域,可以在其中写入数据,并提供一种从应用程序将信息导出到用户可以访问ic或与其他应用程序共享ic的位置的方法.当我们使用这种类型的存储时,应用程序无权访问其存储所在的实际绝对路径.如果您尚未使用WSA或隔离存储,则这种处理文件的方式将需要一些时间来习惯. 为了说明不同之处,以下两个代码块来自将" Hello World"写入文件的桌面.Net应用程序,以及将相同文本写入文件的UWP应用程序.对于这两个代码块,我都尝试了最少的调用次数以完成任务.
//writing to a files on a .Net desktop application
using(StreamWriter sw = new StreamWriter("readme.txt"))
{
sw.WriteLine("Hello World");
}
//writing to application storage in a UWP application
StorageFolder storageFolder = ApplicationData.Current.LocalFolder;
StorageFile storageFile = await storageFolder.CreateFileAsync("readme.txt", CreationCollisionOption.ReplaceExisting);
using (Stream stream = await storageFile.OpenStreamForWriteAsync())
{
using (StreamWriter sr = new StreamWriter(stream))
sr.Write("Hello World");
}
虽然在第二代码块中有更多的调用来写入文件,但它在安全性和应用程序的响应性方面具有优势.在安全方面,对保存文件的完整路径的访问可以向应用程序间接公开有关个人的个人标识信息.由于写入的数据如此之小,因此对响应性的影响差异可能是无法察觉的.随着要写入的数据量或要执行的操作变得越来越重要,这两种写入文件方法在用户体验差异方面的差距越来越大.
应用程序视图的类型
在HoloLens上运行的应用程序可以归类为具有二维视图或全息视图.使用2D视图的应用程序通常可以在其他UWP实现中运行.它们就是所谓的常规应用程序.在HoloLens上运行时,可以将2D视图放置在空间中并保持其位置.如果指定了文本输入字段,则会在HoloLens上显示一个虚拟键盘.当HoloLens支持鼠标时,一个人通常不会使用鼠标,而是通过注视要选择的元素来控制项目选择,并做出选择手势.全息应用程序可控制HoloLens的整个视图.一个其他的应用程序在运行时将不可见.
构建我们的第一个UWP应用程序
该第一个应用将具有微不足道的复杂性.我们将构建一个文本编辑器.尽管这是一个简单的应用程序,但是如果您尚未进行任何UWP开发,它可能会带您进入尚不熟悉的领域.作为可选练习,您可以尝试将此应用程序部署到UWP系列中的其他类型的设备.启动Visual Studio 2015 Update 2并创建一个新项目.创建一个新项目.选择"空白应用程序(通用应用程序)",然后将项目命名为TextEditor.您将看到一个对话框,可让您选择应用程序支持的最大和最小内部版本号.为了跨设备兼容(因为您的设备可能具有不同的版本),请将支持的最小值保持为可用的最小值.在名为" ViewModels"的项目中创建一个新文件夹.现在,将为文件名和文档内容添加几个属性.这些属性将通过数据绑定公开.为此实现了" INotifyPropertyChanged".视图模型的实现如下所示.
using System;
using System.ComponentModel;
using System.Linq.Expressions;
namespace TextEditor.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
string _fileName;
public string FileName
{
get { return _fileName; }
set
{
if(_fileName!=value)
{
_fileName = value;
OnPropertyChanged(() => FileName);
}
}
}
string _text;
public string Text
{
get { return _text; }
set
{
if(_text != value )
{
_text = value;
OnPropertyChanged(() => Text);
}
}
}
protected void OnPropertyChanged(string propertyName)
{
if(PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
protected void OnPropertyChanged<T>(Expression<Func<T>> expression)
{
OnPropertyChanged(((MemberExpression)expression.Body).Member.Name);
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
还要在名为" Views"的项目中新建一个文件夹.编辑器视图将包含一个文本框编辑和一个保存按钮.在"视图"文件夹中,创建一个名为" EditorView.xaml"的新UserControl.
<UserControl
x:Class="TextEditor.Views.EditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TextEditor.Views"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300"
d:DesignWidth="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Button Content="Save" />
<TextBox Grid.Row="1" TextWrapping="Wrap" AcceptsReturn="True" Text="{Binding Text, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<TextBlock Grid.Row="2" >
<Run Text="Character Count:" />
<Run Text="{Binding CharacterCount}" />
</TextBlock>
</Grid>
</UserControl>
如果按调试按钮,它将立即在您的计算机上运行.在尝试在hololens上运行它之前,让我们添加保存和加载功能.必须使用FileOpenPicker
和SaveFilePicker
来获得对文件流的引用.程序将有权访问的关于文件的唯一信息是文件名,而不是路径.文件选择器需要应用程序要处理的文件扩展名列表.调用时将显示文件选择器,用户选择一个文件,然后文件流返回到我们的程序.
public MainViewModel()
{
FileTypeList = new Dictionary<string, IList<string>>();
FileTypeList.Add("Text Document", new List<string>() { ".txt", ".text" });
FileTypeList.Add("HTML Document", new List<string>() { ".htm", ".html" });
}
async void SaveFile()
{
FileSavePicker fileSavePicker = new FileSavePicker();
foreach(string key in FileTypeList.Keys)
{
fileSavePicker.FileTypeChoices.Add(key, FileTypeList[key]);
}
StorageFile file = await fileSavePicker.PickSaveFileAsync();
if(file != null)
{
CachedFileManager.DeferUpdates(file);
await FileIO.WriteTextAsync(file, Text);
FileUpdateStatus status = await CachedFileManager.CompleteUpdatesAsync(file);
FileName = file.Name;
}
}
async void OpenFile()
{
FileOpenPicker fileOpenPicker = new FileOpenPicker();
foreach (string key in FileTypeList.Keys)
{
foreach(string extension in FileTypeList[key])
{
fileOpenPicker.FileTypeFilter.Add(extension);
}
}
StorageFile file = await fileOpenPicker.PickSingleFileAsync();
if (file != null)
{
Text = await FileIO.ReadTextAsync(file);
FileName = file.Name;
}
}
还必须将界面中的按钮绑定到命令,以便可以在用户界面中调用它们.需要编辑" EditorView.xaml"的XAML
<Button Content="Save" HorizontalAlignment="Stretch" Command="{Binding SaveFileCommand}" />
<Button Content="Load" Grid.Column="1" HorizontalAlignment="Stretch" Command="{Binding OpenFileCommand}" />
在本地计算机上运行程序.添加几行并保存文件.如果将文件保存到OneDrive帐户,则可以从其他设备上使用该文件.尽管所有这些设备都将允许应用程序运行,因为我们将看到某些设备可能尚未安装文件选择服务.尽管"写到处运行"的梦想尚未实现.距离很近.不同机器之间的差异在于功能和服务的存在与否之间,将有可能在共享更多源和逻辑的设备之间构建应用程序.
跨设备部署
本节后面的大部分内容是如何部署到支持UWP应用程序的各种设备类型.如果您对这些其他设备不感兴趣,则可能需要跳至HoloLens部署部分.您可能会部署到要在其上进行编程的设备,通过USB电缆连接到开发计算机的设备或通过网络连接的设备.您可能还针对不同的处理器体系结构.两者都需要指定.工具栏上有一个面板,无论您是针对基于x86,x64还是基于ARM的处理器,都可以选择"调试"或"发布"版本.运行burron中还有一个下拉列表,您可以用来选择预期的部署目标.
- 本地机器
- 仿真器
- 遥控机
- 设备
- HoloLens仿真器
- 移动模拟器xxxx 如果选择"远程计算机"作为目标,则需要设置目标设备的IP地址或名称.为此,请在解决方案资源管理器中右键单击您的项目,然后选择"属性".在调试选项卡上,您可以设置远程计算机的地址或名称.仅将启用此功能将"远程计算机"选择为部署目标.
Windows 10移动部署
如果您使用的是Windows 10移动设备,则只需进行一些更改即可将其部署到手机上.对于部署设置的下拉菜单,将处理器架构从" x86"更改为" ARM".如果您从未部署过Windows 10移动设备,则需要更改设置.在设备上,导航至"设置",“更新和安全性"和"面向开发人员”.在"使用开发人员功能"下,选择"开发人员模式".使用USB电缆将手机连接到计算机,然后运行应用程序.它将部署到电话并运行.
Xbox One部署
Xbox One应用程序商店中有一个名为"开发模式激活"的应用程序.下载并运行该应用程序.它将为开发部署准备Xbox One.您将需要30 g的驱动器空间供该应用程序使用.当您通过应用程序启用开发模式时,它将重新启动Xbox One.最好将其视为好像操作系统的另一个实例正在从另一个分区运行.开发模式下可用的Xbox One内容与主分区上的内容是隔离的. Xbox重新启动后,选择" Dev Mode Home". (注意:从此以后,我将USB键盘连接到Xbox,因为使用真实键盘而不是屏幕键盘更容易编辑某些文本设置).请记下Xbox的IP地址.它将显示在此屏幕上.在Visual Studio中,右键单击您的项目,然后选择"属性".在"调试"选项卡中,确保已选择"远程计算机",然后在此处输入xbox的IP地址.将"平台"设置设置为" x86".当您尝试运行该程序时,将收到提示,通知您需要将设备与Visual Studio配对的代码.从DEV HOME控制台中选择"与Visual Studio配对"以获取代码.输入显示在Xbox屏幕上的代码.该应用程序将部署并运行.但是,您会注意到FileOpenPicker
和FileSavePicker
没有响应. Xbox One尚不支持文件选择器.如果计划将其包含在要支持的平台中,则需要查看尚不支持的API(参见此处),然后让您的应用正常退出或使用其他功能.
Windows IOT核心部署
在撰写本文时,有几种可以运行Windows IOT核心的嵌入式设备.这包括Raspberry Pi 2和3,Minnowboard Max以及其他一些主板.这些板的安装说明通常涉及将存储卡插入计算机,然后运行Windows IoT仪表板.它可以选择设置新设备.选择您的设备类型和存储卡,然后选择"下载并安装"
写入存储卡后,将其插入设备,连接网络电缆,然后使其启动.请注意,设备第一次启动可能会花费很长时间.设备启动后,它应该显示IP地址等信息.部署将需要此信息.您也可以从Windows IOT仪表板获取设备的IP地址.
部署该应用程序将非常类似于Xbox One.右键单击项目,选择"属性",然后选择"调试"选项卡.将"目标设备"更改为"远程计算机",将"远程计算机"设置中的IP地址设置为Windows IOT设备的IP地址,然后将"身份验证模式"设置设置为"通用(未加密协议)“应用程序,它将部署并运行到Windows IoT设备.您将能够成功编辑文本,但是与Xbox One一样,SaveFilePicker和OpenFilePicker似乎无法正常工作.一种解决方案是首先检测运行程序的计算机是否可以访问文件选择器,如果操作系统未提供文件显示器,则显示我们自己的文件选择器.我将在以后的文章中讨论如何做到这一点.
部署到HoloLens
部署到HoloLens非常类似于部署到其他设备.您需要获取HoloLens的IP地址.如果打开"设置"应用程序并选择"网络和Internet”,则在选择"高级选项"时将显示IP地址.更新项目属性中的IP地址.导航回到"设置"应用程序的主页,然后选择"更新和安全性".选择" Dfor dveloper"选项卡,然后打开"开发人员模式".您现在可以运行该程序.VisualStudio将部署该设备,然后它将开始最初,您会注意到FileOpenPicker
和FileSavePicker
不起作用,但是系统会提示您一个对话框,提示您安装其他程序后将可用.打开设备的应用商店并搜索并安装OneDrive.安装完成后,如果您返回到应用程序,选择器将立即响应.
使用全息视图构建应用程序
我演示的第一个应用程序没有利用HoloLen在现实世界上叠加渲染对象的能力.下一个应用程序将做到这一点.仍然需要Visual Studio 2015 Update 2,但我们将从Unity开始.在撰写本文时,HoloLens开发所需的Unity构建仍是beta.如果尚未安装,则需要在Unity网站上找到最新的版本.您需要从该站点安装Unity编辑器和UWP运行时.将它们都安装后,启动Unity.如果您已经拥有一个Unity帐户,则需要登录.如果没有,创建一个帐户是容易和免费的.登录后,选择创建新项目的选项.
确保启用了3D选项,然后选择"创建项目". 在下一节中,我将通过名称引用Unity编辑器的区域.下图将帮助您确定区域在哪里.请注意,此放置假定您具有默认布局,并且未更改UI元素的位置.
- 层次结构
- 项目
- 资产
- 检验员
- 现场
创建项目后,需要在Unity中为HoloLens更改一些设置.打开"编辑"菜单,选择"项目设置",然后选择"播放器".播放器设置将出现在右窗格中.确保已设置"虚拟现实"复选框,并且" Windows Holographic"显示为受支持的耳机.如果看不到" Windows Holographic",请单击其下方的加号按钮将其添加.相机上的设置也需要更新.在"场景"布局(左侧窗口区域)中,单击"主摄像机".相机属性将显示在右侧.在"变换"下,将X,Y和Z设置全部设置为零.在"相机"下,将"清除标志"设置为"纯色",并将"背景色"设置为黑色.这将导致HoloLens在没有对象的地方呈现黑色.在HoloLens上,黑色与透明相同. 如果我们现在要运行该应用程序,那就没什么了.让我们在世界空间中放置一些对象,以便我们可以看到一些东西.现在,我们将使用Unity中内置的基本几何对象.在"层次结构"视图中,右键单击空白区域,然后选择" 3D对象",然后选择"多维数据集".单击场景层次结构中的"多维数据集"以编辑其属性.将其"位置"设置为0.0\0.5\4.这会将立方体放置在摄像机前面的某个位置,该位置似乎在4米之外.为确保其位置正确,请单击
如果一切顺利,则下一步是将项目从Unity导出到Visual Studio.打开"文件"菜单,然后选择"构建设置".从平台列表中选择" Windows Store".将SDK版本设置为"通用10",选择"构建".如果您之前曾使用过Unity项目,那么此时Unity通常会构建一个可以运行的应用程序.对于此项目,这仍将导致创建Visual Studio项目.从Visual Studio部署项目.选择"生成"时,将提示您在其中写入项目的文件夹.我通常创建一个名为" App"的文件夹,该文件夹是项目文件夹的子文件夹,然后选择它. Unity将构建项目,完成后将打开文件资源管理器以显示包含新项目的文件夹.打开文件夹以找到项目的解决方案文件并打开它.您可以使用以前用于部署到HoloLens的相同步骤将其部署到HoloLens.当应用程序开始运行时,您应该看到多维数据集漂浮在您面前.可以在立方体周围走来走去,望着它. HoloLens会跟踪您的动作并根据您的动作调整相机.这无需我们编写任何代码即可起作用.让我们尝试一些不同的东西.
Unity,GameObjects和代码
统一体内的对象由许多组件组成.从左侧的场景中选择对象时,构成对象的组件将显示在右侧的层次结构中. .我们将创建一个更具交互性的项目.它将能够识别轻击手势,口头命令,并且注视将在此交互中起作用.我们将制作一个简单的游戏,其中飞机飞来飞去,我们可以瞄准并射击.在Unity中,打开文件菜单,然后选择新建项目.像以前一样为UWP应用程序启用VR支持. 我们需要制作两个视觉效果来代表导弹和飞机.理想情况下,这些将由导入到Unity中的外部资产制成.我将使用Unity中内置的几何对象创建占位符.我们可以稍后替换它们.让我们先做个菜包.在右侧的层次结构面板中,右键单击空白区域,然后选择"创建空白".此空对象将用作组成该杂物的所有对象的公共父对象.在右侧检查器中选择了新游戏对象后,将其重命名为Missle.我们将要利用Unity内置的物理引擎.在"检查器"面板中,单击"添加组件",然后选择"物理"和"刚体".确保其位置为(0,0,0),旋转角度为零,并且X轴,Y轴和Z轴的比例都设置为0.新重命名的空白游戏会弹出并选择" 3D对象",然后选择"圆柱体".这将形成导弹的主体.确保圆柱体的位置是(0,0,0).仅将X轴旋转90度.将Y轴的比例设置为2.右键单击" Missle",然后创建一个新的球体.将其位置设置为(0,0,2).这将是团长.在方块中创建一个多维数据集.将其Z位置设置为-1.5.将其X比例设置为1.5,将其Y比例设置为0.1,并保持Z比例为1.创建另一个立方体,并将其Z位置设置为-1.5. x比例尺需要设置为0.1,Y比例尺需要设置为1.5.该构造的最终结果如下图所示.
重复相同的步骤制作飞机;创建一个空对象并向其添加3D对象以近似一个平面.我在下表中列出了组成平面的子对象及其设置. 如果使用上述修改创建了对象,则最终应类似于以下内容.
添加代码
在屏幕底部的"项目"面板中,单击"资产"文件夹.在此文件夹右侧的窗格中,右键单击空白区域,然后依次选择"创建"和" C#脚本".将此新脚本命名为" PlaneBehaviour".双击脚本以在编辑器中将其打开.您在Unity中创建的大多数类都将从基类MonoBehaviour继承.虽然在Unity中声明自己的派生类实现时可能已经使用了方法重写,但是通过简单地使用具有相同名称和调用参数的方法就可以完成相同的任务.它实际上不需要使用override
关键字.您需要在类中进行的任何初始化都将在Start()方法中完成.将定期调用名为Update()的方法.我们大多数的游戏逻辑将在这里进行.空的Start()和Update()将已经存在于新类中.可以添加其他方法.
" PlaneBehaviour"类将跟踪飞机是否正在飞行或坠毁,飞行了多长时间或坠毁,并在经过一定时间后将其移除.
using UnityEngine;
using System;
using System.Collections;
public class PlaneBehaviour : MonoBehaviour {
public enum PlaneState
{
Flying,
Crashing
}
public PlaneState State;
public double CrashTime = 5.5d;
public float TimeToLive = 30;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
if (State == PlaneState.Crashing) {
CrashTime -= Time.deltaTime;
if (CrashTime < 0)
Destroy (this.gameObject);
} else {
TimeToLive -= Time.deltaTime;
if (TimeToLive <= 0)
Destroy (this.gameObject);
}
}
}
对于我们的导弹,我们将有类似的需求.编写另一个名为MissleBehaviour
的C#脚本.如果导弹与飞机接触,它将受到重力的影响.如果偶然碰巧撞到另一架飞机,也将导致其坠毁. Unity将为我们检测冲突.我们只需要决定如何对他们做出反应.除了Start()代码>和Update()方法外,我们还将有OnCollisionEnter(Collision col)方法.该方法接收的参数是与我们的导弹碰撞的物体的信息.我们将检查另一个对象是否是飞机.如果是,那么重力将被允许影响导弹的运动.为此,我们将引用GameObject
using UnityEngine;
using System.Collections;
public class MissleBehavour : MonoBehaviour {
public float Lifetime = 5;
// Use this for initialization
void Start () {
}
// Update is called once per frame
void Update () {
Lifetime -= Time.deltaTime;
if (Lifetime < 0)
Destroy (this.gameObject);
}
void OnCollisionEnter(Collision col)
{
var plane = col.gameObject.GetComponent<PlaneBehaviour> ();
if (plane != null) {
var rigidBody = GetComponent<Rigidbody> ();
rigidBody.useGravity = true;
}
}
}
我们希望飞机与导弹碰撞时进入坠毁状态.返回" PlaneBehaviour"类,并向其添加" OnCollisionEnter"方法.如果飞机已经坠毁,则该方法不应执行任何操作并立即返回.如果确实发生碰撞,我们将检查它是什么.如果另一个碰撞物体是一架飞机,则什么也不做(尽管物理引擎可能会导致飞机开始翻滚,但这很好).如果另一个物体是导弹,则将飞机的当前状态标记为坠毁,并让其屈服于重力.我还将在飞机上添加引擎的声音效果.但是,如果飞机开始坠毁,我希望声音关闭.
void OnCollisionEnter(Collision col)
{
if (State == PlaneState.Crashing)
return;
var missle = col.gameObject.GetComponent<MissleBehavour> ();
if (missle != null) {
State = PlaneState.Crashing;
GetComponent<Rigidbody> ().useGravity = true;
AudioSource source = gameObject.GetComponent<AudioSource> ();
if (source != null)
source.enabled = false;
}
}
要将音效添加到飞机上,我需要在计算机上找到合适的声音文件(Unity支持多种不同的音频文件格式),并将其从计算机上的资源管理器中拖到素材资源文件夹中.从项目层次结构中选择我的飞机我可以在检查器中选择"添加组件",选择"音频",然后选择"音频源".向AudioSource分配声音,然后单击声音文件并将其从"资源"面板拖到检查器中的"音频剪辑"设置.
生成飞机和导弹
现在,我们已经定义了飞机和导弹,我们需要将它们保存为可重用的形式.按照他们目前的形式,如果我们要运行程序,那将是一架飞机和一个悬在空中的小盾,什么也没做.我希望飞机能够实例化任一飞机的副本并为其分配不同的速度.每个实例都需要维护自己的状态.为此,我们需要将飞机和导弹转换为预制件.从Hierarchy面板到Assets面板,单击并拖动用作平面根部的gameObject.对Missle做同样的事情.确认它们都出现在资产中后,您可以将它们从场景中删除. 创建一个名为" PlaneGeneratorBehaviour"的新C#脚本.此行为将具有两个可以更改的设置.一种设置是在实例化新飞机之间等待的时间.另一个将是此类将要生成的类型的" GameObject".此类需要跟踪的其他信息是,直到可以生成下一个平面为止的剩余时间.我们还将需要一个随机数生成器来定位新飞机.随机数生成器将在类的Start()方法中初始化.
public float ProductionCooldownTime = 1;
public GameObject PlanePrefab;
private float _cooldownTimeRemaining ;
System.Random _random;
// Use this for initialization
void Start () {
_random = new System.Random ();
}
对于每个" Update()“周期,该类将使” _cooldownTimeRemaining"字段减少自从上次" Update()“运行(在” Time.deltaTime"中找到)以来经过的时间.如果_cooldownTimeRemaining大于零,则无需执行任何操作,该方法立即返回.如果它小于或等于零,那么该是生成新平面的时候了.重置该字段的值以开始下一次倒数,并使用Unity的GameObject Instantiate(GameObject source)方法制作该平面的副本. 飞机的相对位置在名为VectorPosition的Vector3实例中定义.实例化范围内的随机值.定义了穿过该平面的垂直轴,并将该平面旋转了一定数量的随机度以选择其方向.使用Unity的内置物理引擎,我们将获取对飞机的"刚体"组件的引用,并在与飞机强制为其施加动量的方向相同的方向上对其施加力.
using UnityEngine;
using System.Collections;
public class PlaneGeneratorBehaviour : MonoBehaviour {
public float ProductionCooldownTime = 1;
public GameObject PlanePrefab;
private float _cooldownTimeRemaining ;
System.Random _random;
// Use this for initialization
void Start () {
_random = new System.Random ();
}
// Update is called once per frame
void Update () {
_cooldownTimeRemaining -= Time.deltaTime;
if (_cooldownTimeRemaining > 0)
return;
_cooldownTimeRemaining = ProductionCooldownTime;
Vector3 newPosition = new Vector3 ();
newPosition.x = (float) _random.NextDouble () * 20 - 10;
newPosition.y = (float) _random.NextDouble () * 10 - 5;
newPosition.z = (float) _random.NextDouble () * 20 - 10;
var newPlane = Instantiate (PlanePrefab);
newPlane.transform.position = newPosition;
Vector3 rotationAxis1 = newPlane.transform.position;
Vector3 rotationAxis2 = newPlane.transform.position + new Vector3 (0, 1, 0);
Vector3 newAngle = new Vector3 (0, (float)_random.NextDouble () * 180, 0);
newPlane.transform.Rotate (newAngle);
Rigidbody _body = newPlane.GetComponent&ht;Rigidbody> ();
_body.AddForce (Quaternion.Euler(newAngle) * new Vector3(0,0,90));
}
}
保存脚本.在层次结构中创建一个空的游戏对象,然后从资产面板中将" PlaneGeneratorBehaviour"拖到刚创建的空游戏对象中.如果单击场景上方的"播放"按钮,将看到正在运行的场景的预览.
我们还需要一个脚本来进行用户交互.从较早的示例中,您看到相机将自动跟随用户的移动.我们将查看相机的位置和方向,以便在她射击时,一个导弹将以相同的方向出现并向前移动.该脚本将使用Missle预制件.有两种射击方法.可以做出AirTap手势,或者用户将能够说出"开火"一词. HoloLens支持两种语音识别模式.一种模式是听写,然后将用户所说的内容转换为文本.另一种模式是让HoloLens监听预定义短语列表,并在听到其中一个短语时触发事件.我们将使用这两种模式中的后者.要使用此模式,我们启动一个" KeywordRecognizer".它需要包含将识别的短语的字符串数组.对于我们的程序,此数组将包含一个带有字符串" fire"的元素.识别该单词将导致设置一个标志,指示用户已请求发射导弹. 为了识别轻击手势,我们将使用" InteractionManager".该课程将提供有关用户手部运动的信息.我们唯一关心的信息是用户刚刚做出了空中点击手势.当检测到标志时,将设置指示用户已请求发射导弹的标志.
public float CoolOffTime = 2;
public GameObject MisslePrefab;
private float CoolOffTimeRemaining = 0;
private bool IsFirePressed = false;
KeywordRecognizer _keywordRecognizer;
void Start () {
InteractionManager.SourcePressed += (e) => {
if(e.pressed)
IsFirePressed = true;
};
_keywordRecognizer = new KeywordRecognizer (new string[] { "fire" });
_keywordRecognizer.OnPhraseRecognized += (o) => {
if(o.text=="fire")
{
IsFirePressed = true;
}
};
_keywordRecognizer.Start ();
}
触发请求并不一定会导致实际触发.我只想让导弹每隔几分钟就被发射一次.如果我们仍处于冷静期,则Update()方法将立即返回.如果冷却时间结束,我们将检查触发标志是否已设置.如果设置了该标志,则清除该标志,重置冷却时间,并实例化一个粒子.我们查看Camera对象,并获取其位置和旋转并将其应用于框.最后,对导弹的" RigidBody"代码>组件进行了推进.
void Update () {
CoolOffTimeRemaining -= Time.deltaTime;
if (CoolOffTimeRemaining > 0)
return;
if ((IsFirePressed)) {
IsFirePressed = false;
CoolOffTimeRemaining = CoolOffTime;
GameObject missleObject = Instantiate (MisslePrefab);
Camera camera = GetComponent<Camera> ();
missleObject.transform.position = camera.transform.position + camera.transform.forward * 2.0f;
missleObject.transform.rotation = camera.transform.rotation;
missleObject.gameObject.GetComponent<Rigidbody> ().AddForce (camera.transform.forward * 250);
}
}
该脚本必须拖到MainCamera组件上.您还需要将预制件的导弹拖到组件上显示的MisslePrefab
属性中.完成此操作后,您可以创建另一个Visual Studio构建.在Visual Studio中部署构建之前,请双击名为Package.appmanifest的文件.该程序将需要使用设备麦克风的权限,我们将使用清单请求权限.打开清单后,选择"功能"选项卡,然后向下滚动到"麦克风"功能.确保已检查.
导入资产
3D建模是其自身的特色.我不会在这里介绍如何使用3D建模工具.确实存在允许建模者出售附加了不同使用许可的作品的网站.为了演示使用外部资产,我将转到TurboSquid,并寻找价格在0.00美元至1.00美元之间的导弹模型.
我选择并下载了导弹模型.它们有多种格式.我选择了OBJ文件并将其拖到我的Unity Assets中.一旦资产的一部分,我将其拖到场景中.对比例进行了一些调整,直到使我满意为止.通过单击并拖动将" MissleBehaviour"脚本添加到其中.使用检查器中的"添加组件"按钮,我添加了一个RigidBody组件(在"物理"下),并将其质量设置为0.24.同样从Physics,我添加了一个Capsule Collider.我调整了Capsule Collider的大小和位置,直到它刚好包裹住了导弹.当我对所有外观感到满意时,我将该实例命名为SmartMissle,然后将其拖回Assets以创建新的预制件.最后,我用新的SmartMissle替换了" PlayerBehaviour"脚本中(相机对象上)的Missle.再次运行该程序,我看到了详细的导弹,它代替了上一个.如果您没有HoloLens,并且想查看该程序的外观,那么我已将记录上传到YouTube,可以在此处访问.
结束语
为HoloLens进行开发还有很多内容.其中包括许多概念和技术,这些概念和技术是Unity的一部分,可移植以针对Unity支持的其他平台,以及许多HoloLens特有的功能.如果您不熟悉HoloLens开发,我建议您从三个方面进行深入研究.深入研究UWP应用程序而不是特定于HoloLens会有所帮助,因为您将学习适用于所有UWP设备(包括HoloLens)的概念,代码和API.深入研究Unity将有助于学习如何为HoloLens构建交互.微软在其站点上还有一个区域Holographic Acadamy,其中包含有关HoloLens特定Unity功能的大量信息例如扫描环境以了解其中的其他对象. 我计划写很多有关UWP开发的信息,包括HoloLens.如果您对UWP的特定领域感兴趣,并且希望我以后再写这些文章,请务必在下面发表评论. 我还要感谢K.A.P.他的鼓励促使我发表了这篇文章以及其他不久将要发表的其他文章.
历史
- 2016年6月16日
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# Windows Dev Intermediate 3D WinRT Unity VS2013 Unity3D 新闻 翻译