Image source: https://www.windowscentral.com/microsoft-hololens
Guest post by Sondre Agledahl, Microsoft Student Partner at University College London. I am a games programmer, excited to see how emerging technology can be used to make completely new and meaningful immersive experiences (and to be young enough to take full advantage of it!). Avid ROM hacker and karaoke enthusiast. Computer Science student at UCL.
The possibilities for creating new and novel gaming experiences using mixed reality are really endless, and we have only so far seen the tip of the iceberg of what can be achieved with this new technology.
As a developer looking to pioneer the creation of some of these new immersive experiences, you’ll be happy to find that an extensive library of open-source tools already exist to quickly and easily make the transition to mixed reality development. Notably, Microsoft’s own HoloToolkit for Unity includes a complete Unity package, replete with scripts, components and prefabs for interacting with the HoloLens device.
What follows is a simple tutorial that introduces the core elements of HoloLens development in Unity (gaze, gesture, voice recognition, and spatial awareness). Starting from scratch, we will create a highly customisable Unity project where you can fire virtual arrows with your fingertips, to interact with our own holograms, as well as with the real world around you.
The finished game can be deployed either to your own HoloLens device (should you be lucky enough to have one!) or to the official HoloLens emulator.
Section 1 – Installing the tools
Firstly, you’ll want to make sure that your development PC is running Windows 10, as no other operating system currently supports HoloLens development.
From here, the following tools are needed to get started:
· HoloLens emulator (if you don’t have access to a physical device)
We’ll walk through the installation process for each of these components in turn:
1. If you haven’t already done so, install the Visual Studio IDE (either the 2017 version, or 2015 with update 3) and the Unity game engine. In fact, you only need to download one of these, as the other program is included as an optional component when installing the other.
2. Make sure you have the newest Windows 10 SDK installed (select the Universal Windows Platform development workload when installing Visual Studio, or download it separately).
3. If you don’t have access to a physical HoloLens device, you can download the free HoloLens emulator to test your projects on your regular PC.
o Note: The HoloLens emulator is not compatible with Windows 10 Home, so if this is your version of Windows, you will have to upgrade to either the Professional, Enterprise or Education editions. If you’re a student, chances are your university can offer you a free upgrade to Windows 10 Education – have a look at your university website and Microsoft Imagine Access http://imagine.microsoft.com
o Activate Hyper-V functionality for Windows by going to Control Panel -> Programs and Features -> Turn Windows features on or off, then select and install Hyper-V.
o If you’re using Visual Studio 2017 (without Visual Studio 2015 installed as well), follow the official Microsoft guidelines for making the emulator compatible with this version:
1. Add or locate this key: HKLM\SOFTWARE\ Microsoft\Analog
2. Add a REG_SZ value in that key with name: “OverrideHoloLensSDKPrerequisites”, and value: “TRUE”
3. If you are on an x64 version of Windows, also add or locate this key: HKLM\SOFTWARE\Wow6432Node\Microsoft\Analog
4. Add a REG_SZ value in that key with name: “OverrideHoloLensSDKPrerequisites”, and value: “TRUE”
Section 2 – Setting up your Unity scene
Start by creating a new 3D project in Unity, and give it an appropriate name (“ArrowMaster” is a good one).
Beginning with our empty Unity scene, we will make some initial adjustments to allow for compatibility with the HoloLens.
First of all, select Edit -> Project Settings -> Player, and click on the green Windows Store logo in the Inspector. Under the Other Settings tab, tick the Virtual Reality Supported box, and make sure Windows Holographic is listed under SDKs. Then, under the Publishing Settings tab, find the Capabilities list, and tick the Microphone and SpatialPerception boxes, giving Unity permission to make use of these features.
Next, we want to make sure our game runs as smoothly as possible (slowdowns can cause our players to get sick), so we’ll lower the graphics quality for our build. Go to Edit -> Project Settings -> Quality, then click on the small arrow icon under the Windows Store logo in the Inspector and select Fastest.
From here we will make a few adjustments to our scene’s Main Camera to set it up in such a way that it can represent our player, with the player’s position and head rotation represented by the Camera’s. First, reset the Camera’s Transform component so that its position is centred at the origin (that is, position (0, 0, 0)).
Next, under the Camera component, find the Clear Flags option and select Solid Color. Under Background set the camera background colour to solid black (RGB (0, 0, 0)). Everything our Main Camera in Unity currently sees as black will represent the real world behind our holograms to our player.
Finally, to make sure our holograms don’t render too close to the player’s face, set the Clipping Planes -> Near option to the HoloLens recommended 0.85.
Now we’re ready to import our HoloLens-tailored assets. Select Assets -> Import package -> Custom package… and select the location where you’ve unpacked this project’s asset package.
This package includes a copy of Microsoft’s HoloToolkit assets, as well as a couple of simple object prefabs. (If you would rather create your own GameObjects for this project from scratch, please do! OpenGameArt and FreeSound.org are some excellent starting resources.)
Through the project explorer, go to the HoloToolkit -> Input -> Prefabs -> Cursor folder, and drag the DefaultCursor prefab into your scene hierarchy. This cursor object will represent the point the player is currently looking at through their HoloLens.
Next, select GameObject -> Create empty to create a new empty GameObject in your scene and rename it “Managers”. Find the HoloToolkit -> Input -> Prefabs folder and drag the InputManager prefab onto your Managers object to child it to this object in your scene hierarchy.
Find the HoloToolkit -> SpatialMapping -> Prefabs folder and drag the SpatialMapping prefab into your scene as a child of the Managers object in the same way. This object is responsible for giving Unity information about the HoloLens’s mapping of the player’s surroundings.
Then, click on your SpatialMapping instance in the scene hierarchy and find its components in the Inspector tab. Under the SpatialMappingManager script component, you will see the “Draw Visual Meshes” box. When this is ticked (i.e. set to true), our application will draw a wireframe representation of the spatially mapped environment surrounding the player while the game is running.
If you’re deploying your game to a physical device, I recommend unticking this box, as it is largely unneeded for our purposes, and consumes unnecessary performance. If you’re deploying to the HoloLens emulator, however, feel free to leave the box ticked, as it can give you a useful visualisation of the virtual room you’ll be playing in.
Next, with your SpatialMapping instance still selected, click on Add Component, and add a Spatial Mapping Collider to the object. This effectively assigns a collider component to the player’s real-world surroundings, allowing us to make our holograms collide with a real-world environment in a realistic (or unrealistic – whichever you prefer!) way.
Finally, add an EventSystem to your scene by right-clicking on your Managers object, and selecting UI -> Event System.
With these preliminaries out of the way, we’re all set to develop HoloLens applications, and are ready to make something new!
Section 3 – Firing virtual arrows
The first thing we want to do in our game is to allow our player to fire arrows by tapping his or her finger. We will accomplish this by writing a script and attach it to our Main Camera object. Using a GestureRecognizer, we will set up an event listener for a “Tap” event, and assign it to a callback method that instantiates and fires an Arrow object in the direction of the user’s gaze.
Included in the Prefabs folder in the root of your project explorer, you will find an Arrow prefab that we will use for this purpose. This Arrow comes with a Collider, RigidBody and AudioSource already attached and configured.
We’ll start by giving our Main Camera an AudioSource to play a “whoosh” sound as we fire our arrows. Navigate to the Sounds folder, and drag the Arrow flight.mp3 file onto the Main Camera object in the hierarchy. Looking at your Main Camera in the Inspector, you will see that an Audio Source component has been added. Edit its properties so that Play On Awake is unchecked (so our arrow sound doesn’t play when the game starts) and Spatial Blend is set to 1.
Now, with your Main Camera object still selected in the hierarchy, add a new script component to it called Bow. This will be the script we’ll use to fire our arrows. Double-click on your new Bow.cs script to open it in Visual Studio.
If you already have experience writing scripts in C#, I would encourage you to write this script yourself, consulting the Unity Docs for more information about the GestureRecognizer object. If this is not something you’re familiar with, or you get stuck while coding, I’ve included my implementation below, that you can copy and paste into your Bow.cs file.
In summary, our Bow script needs to do the following (remember to include the UnityEngine.VR.WSA.Input namespace to access the GestureRecognizer object!):
1. Access our Arrow prefab
2. Set up a GestureRecognizer to recognise “Tap” events
3. Invoke a callback method for each “Tap” event for shooting our arrow
4. Play our arrow flight sound
5. Instantiate our Arrow prefab at the current position and rotation of the camera
6. Apply a force to the arrow so that it shoots forwards
Now, having exposed arrowPrefab as a public GameObject in the Bow script, it will show up as an empty field in the Inspector when the Main Camera object is selected. Locate this empty Arrow Prefab field, then navigate to the Prefabs folder, and drag the Arrow prefab into this empty field. Now the Bow script will have access to this our Arrow prefab and will instantiate it in the Shoot method.
Well done! The player can now use their fingers as a virtual bow and arrow! Of course, working from the Unity editor alone you wouldn’t know. If you’d like to try to build and deploy your project at this stage, you can jump ahead to Section 6 of the tutorial and fire away (you can do this as many times as you like throughout the project to test your implementations).
Now, with this behaviour in place, our fired arrows will bounce off of the player’s real-world surroundings (because of the Spatial Mapping Collider we attached to our SpatialMapping object earlier). While this is quite a novel thing to see in action by itself, it’s not exactly the behaviour we would expect from an arrow. What we want is for our arrows to stick to the objects they collide with.
There are a number of approaches we could take to creating this “sticky” behaviour, but thankfully Unity allows us to use a very simple and straightforward solution: By setting our Arrow’s RigidBody component to Kinematic (signifying that we don’t want the object to conform to Unity’s physics engine), we can effectively freeze its position in space whenever we want to.
On top of this, we can make fired arrows continue to stick to the objects they collide with even if these objects move later, by setting each arrow to be the child of the object it collided with in the Transform hierarchy.
We can accomplish these behaviours through a simple script that we attach to our Arrow prefab. Find the Arrow prefab again inside the Prefabs folder, and add a new script component to it called Arrow. Open it up in Visual Studio.
To recap, we need our Arrow.cs script to accomplish the following:
1. Whenever it collides with something, play its attached collision sound
2. Set its RigidBody component to be Kinematic
3. Child it to the GameObject it collided with in the Transform hierarchy
If you have difficultly implementing any of the above, check my implementation below:
You now have a set of responsive, semi-realistic arrows to fire! Again, feel free to jump ahead to Section 6 to see how to test your solution, and try sticking arrows all over your furniture (or, if you’re using the emulator, map out the shape of the simulated room by covering it in arrows)!
Section 4 – Something to shoot at
Now that our firing mechanism is in place, it’s time to make our project a little more game-like, by introducing an actual objective. Navigate back to the Prefabs folder, and drag a Target prefab into your scene.
Inspecting the Transform component of your new Target instance, you’ll see that its position is set to (0, 0, 2). By default, the HoloLens treats Unity world units as real-life metres, so the player will see this target initially as being two metres in front of him or her – a reasonable firing range.
Now, you’ll note that the target already comes with a RigidBody and a Collider attached, so you can already fire arrows at the target just and have them stick to it right out of the box. To add an extra layer of interactivity, however, let’s make our target actually respond when the player successfully strikes it with an arrow.
As you can see, our Target comes with an AudioSource and accompanying AudioClip attached. Whenever the player hits the target with an arrow, we want to play this sound, then have the target briefly change colour – both of which indicate to the player that we registered their successful shot. From here, we want to make it so that the target can only be struck a certain number of times before it falls to the floor.
As before, select your Target object, and add a new script component to it called Target. Open it in Visual Studio.
Our Target.cs script will have to accomplish the following:
1. Access the Target’s renderer component to change its colour
2. Play its sound when something collides with the Target
3. Briefly change its colour, then change it back again
4. Check if it has been struck too many times to stay afloat
5. If so, have it fall to the floor
6. Make sure all children objects of the Target fall to the floor as well
As always, feel free to copy my implementation (or to compare it against yours after you’ve finished) if you need some guidance:
Very cool. We now have elements in place for a simple yet satisfying holographic mini-game.
Go ahead and create two more duplicates of your Target object in your scene, and set them up next to each other to form a mini-sized target range. Shown below are our three targets placed at positions (0, 0, 2), (0.5, 0.5, 2) and (-0.5, 0.5, 2) respectively.
Before we move on, there is one more adjustment we can make to our project to ensure players have the smoothest arrow-firing experience possible.
If you’ve already deployed and tested your project thus far, you may have noticed that your arrows can often end up colliding and sticking to each other rather than the target you’re trying to hit. We can prevent this mildly annoying behaviour with a simple tweak to our physics layers.
Find your Arrow prefab again in the Prefabs folder, and in the Inspector, select Layer -> Add Layer… In the first blank User Layer entry, type “Arrows” and press Enter on your keyboard. Find the Arrow prefab again in the Inspector, and set its Layer to our newly created Arrows layer.
Next, in your main Unity menu, select Edit -> Project Settings -> Physics. Inside the PhysicsManager that opens in the Inspector, find the Layer Collision Matrix tab, and uncheck the Arrows-Arrows entry. This will make it so that our arrows will no longer collide with each other, which is going to make for a much less frustrating experience for our players.
Much better. Have a play around with the current state of the project if you want, before we move on to making our final addition to our project – voice commands
Section 5 – Voice control
The last unique element of HoloLens development we are going to touch on is speech recognition. Thankfully, the UnitEngine.Windows API makes setting up voice commands with custom behaviours very simple.
We will make use of a KeywordRecognizer event listener object. This KeyWordRecognizer is initialised with a list of strings containing plain English phrases that we want to use as voice commands, and is set it up like any other event listener. Unity will automatically begin listening for cases of these phrases being spoken through the user’s microphone, invoking our custom callback methods whenever a phrase is recognised.
Let’s implement two speech commands in our little game – one alternative command for firing arrows, and another for resetting the scene so the player can start over.
Select your Main Camera in the scene hierarchy, and add to it a new script component called SpeechControl. Open it up in Visual Studio.
As always, let’s go over exactly what we want this script to accomplish before we write our code. Consult the handy Unity Docs for more information about the KeyWordRecognizer or any other objects or methods you’re unsure about.
1. Remember to include the UnityEngine.Windows.Speech namespace to access the KeyWordRecognizer!
2. Initialise a KeyWordRecognizer with a list of strings (our voice commands)
3. Set up a callback method for a speech recognition event, and start listening
4. When a phrase is recognised, check which one it is
5. Shoot an arrow from the Camera’s Bow script if appropriate
6. Or reload the scene from the beginning
If you managed to successfully implement the above script – well done! You can now bring back your fallen targets as many times as you like.
We now have a fully functioning HoloLens experience that incorporates gaze recognition, spatial mapping and speech commands! In the last section, we will look at how to bring our game to life by building it and deploying it to a real device.
Section 6 – Deploy to Hololens (or emulator)
Before building your project, make sure that your working Unity scene is saved (either through File -> Save Scene or simply pressing CTRL+S). I’ve simply named my scene “Game” and stored it in the root of the Assets folder.
Now, with the current state of your scene open in Unity, select File -> Build Settings. Under the Scenes In Build rectangle that appears at the top of the screen, click on Add Open Scenes to add your main scene to the build if you haven’t already. From here, under Platforms, select Windows Store, and press the Switch Platform button.
Once the target platform has switched, we will make a couple of other minor adjustments to our build settings to target the HoloLens. On the right-hand options list, make sure SDK is set to Universal 10, Target Device to HoloLens and UWP Build Type to D3D. Under the Debugging options, tick the Unity C# Projects box, and press the Build button to build your solution!
Unity will prompt you to select a target folder for your build. Simply create a new folder inside your project (named “App” by convention). After a short wait, your project folder should open up. Open the build folder you just created, and double-click on the Visual Studio Solution (.sln) file inside to open it in Visual Studio (in my case, this is the ArrowMaster.sln inside the App folder).
With the solution open in Visual Studio, find the two dropdown menus next to the green play button at the top of the screen. In the leftmost menu (Solution Configurations) select Release, and in the next menu (Solution Platform) select x86. Finally, expand the dropdown menu right next to the green Start button and select either Device (if you’re deploying directly to a physical HoloLens over USB) or HoloLens Emulator (if you installed it earlier).
Finally, in the top menu bar, select Debug -> Start Without Debugging (or simply press CTRL + F5) to deploy your project. If you’re using a physical HoloLens, the project will load automatically on your device once it has finished building, whereas if you’re using the emulator, you will have to wait for the emulator to finish booting up before the project starts.
If everything worked smoothly and your game runs as it should – congratulations! You have just launched your first self-created mixed reality experience! (For emulator users, use the W-A-S-D keys and your mouse to control virtual movement in your game – or use an Xbox controller).
I hope you enjoyed this brief tutorial on getting started with mixed reality game development. Our little bow-and-arrow game here is really only a very simple example of the sort of experiences you can create for players through Unity’s integration with the HoloLens’s interactive holograms, spatial mapping and gaze and voice recognition technologies.
Hopefully it has given you an idea of just how simple it is to make the transition from conventional 3D game development to Mixed Reality, with virtually no real knowledge of how the technology works under the hood required.
If you’re unsure where to go next in your Mixed Reality development journey, why not try to expand our bow-and-arrow game to add some more novelty and polish? (Feel free to fork the project on GitHub). I can suggest a couple of improvements:
· Let the player switch to an alternate projectile type (a gun, a slingshot?) with slightly different behaviour through the use of a voice command.
· Have the targets spawn in random locations relative to the Main Camera’s position every time the scene is loaded (making sure targets never appear inside of objects in the spatially mapped environment).
· Modify the targets to fire their own projectiles at the player that they have to dodge, and induce a mildly annoying visual effect whenever the player gets hit.
· Set a time limit for the game that is shown to the player. Play an extra jingle if the player manages to break all of the targets within the time limit, and play a sad violin tune if they fail.
From there, if you’re looking to learn more about game development for HoloLens through Unity, I would highly suggest checking out the official Microsoft Mixed Reality guides at the Windows Dev Center website. These include both step-by-step tutorials (Academy) as well as in-depth documentation about how the HoloLens and its software APIs work (Development).
· 3D model for archery set (arrows and targets) by OpenGameArt user yd (Public Domain)
· Arrow flight and impact sounds by FreeSound.org user Robinhood76 (Creative Commons)
· Target hit sound by FreeSound.org user grunz (Creative Commons)
Source Control for the project : https://github.com/colonelsalt/ArrowMaster