Introduction to VR development with Unreal Engine

Henrik Aarnio
Junction
Published in
8 min readApr 12, 2018

--

This blog post was written for the purposes of a workshop at Stupid Hack, an annual event organised by Junction, where the goal is to create the stupidest and most useless projects imaginable. This disclaimer was plagiarized from Juuso, who is also hosting a workshop about React Native.

To follow the most complicated logic in this workshop you should have at least a basic understanding of programming, but we will not be writing any code.

Running the VR applications requires a computer within the high end of processing power, but not having one will not be a problem in just following along. Maybe you can team up with someone who has one!

Prerequisites

In this workshop we are using Unreal Engine 4 and HTC Vive. The list of software to install is as follows:

  1. Epic Games Launcher for installing Unreal engine
  2. Unreal Engine, installed from Epic Games Launcher
  3. Steam, for using Steam VR for running the HTC Vive headset

UE in particular is multiple gigabytes in size, so be aware that the download may take a while.

The objective

We will be making a simple speed tester game, known from gas stations through the country and national hit TV-shows, such as Speden Spelit. The game consists of four lights of different colors, which light up in a sequence which the player has to hit in the right order and fast enough to not lose the game. The lights will be quite far away in our virtual world, so this game will provide a nice bit of exercise as well!

Part 1: Going into the virtual world

Open Unreal Engine from the Epic Games launcher. Begin by choosing the “Virtual Reality”-preset, and click “Create Project”. This will make us a game world with a couple of simple objects and the necessary functionality to move around in the virtual world. Load up “Motion Controller Map” from the content browser at the bottom of the screen by double clicking it. This is the main scene of our game. We will not edit it much, we’ll just add a couple of objects that handle our game mechanics to it.

The main view of Unreal engine. Object listing at right, content browser at the bottom.

At this point the project can already be launched on the Vive from the top of the screen, “Play” button.

We will begin by creating an object to handle all our game logic. To add our own objects to the game world, navigate to Content->Virtual RealityBP->Blueprints from the content browser, and click “Add new”. Select the new object to be a Blueprint, and that it is an actor. We’ll name it SpeedTester. Double click this object to edit it. This will load up a new editor, where we can edit the properties of this object.

The object editing view, with the four buttons we will use in our game.

Let’s begin by creating four balls to act as the buttons to our speed tester. Upper left has the button “Add component”, we’ll just select “Sphere”. Let’s name them “Button1”, “Button2”, “Button3” and “Button4”, and spread them out nicely in the editor view in front of us using the arrows that appear when one is clicked.

Next we want to add materials to the buttons to make them look a little bit nicer. We can do this from the “Material”-section in the object settings on the right side of the screen. Click the dropdown with the material name, and from the top select “Material” from the “Create a new asset”-section. Name it ButtonMaterial1. Double click the small square with the material’s icon to open the material editor. The material editor is node-based, which allows very flexible setup of materials. For now it is enough to add a 3Vector-datatype input (rightclick, Constants->3Vector), and connect it to the base color of the material. Double click the color selection in the 3Vector node to select its color. Hit “Apply” at the top, and repeat the process for the three other balls.

Material Editor. Simple color is enough for now.

Let’s save the SpeedTester file, and return to the editor with the MotionControllerMap open. We can drag the SpeedTester from the content browser to the game world, and position it with the widget. We can rotate the object by hitting E, scale it with R, and go back to moving it with W. Our game has content!

SpeedTester in the game world!

Part 2: Adding interactions

To add interactions to the game, we’ll go back to editing the SpeedTester object. Click the “Event Graph”-tab that is over the 3D-view. This is the graph that controls the behavior and logic of the SpeedTester game object. In the graph the execution flow is marked with a thick white line, connecting nodes that contain functions that take time to execute. The symbol of the execution flow is the white triangle socket on these nodes, they will only be executed when their incoming connection is activated. Variables and references are shown using thinner lines, and connected with circle sockets.

To access our buttons in the game logic, we will want to access them from an array. Let’s construct that by rightclicking and searching for “Make Array”, and dragging the button variables from the lower left into the editor area and connecting them to the array.

Variable section, and making an array from our buttons

Next we want to know when our button is punched. Let’s start from the “Event Tick”-node. Things connected to this socket will be run all the time in the game logic. Let’s connect this to a ForEachLoop node to go through our array and see if any component in it is punched. It will run things connected to the “Loop Body” socket for each of the elements in the array. To detect the collision, we’ll take a ComponentOverlapsComponents node that tells us whether a component, in our case one of the buttons taken from the array, collided with anything. This node returns a boolean value that tells us whether a collision was found. It also requires us to find the transform of the component used, and an array of types to ignore in the checking, so let’s add GetWorldTransform and Make Array -nodes and connect them to the sockets on the ComponentOverlapsComponents.

Our logic this far

To finish off, we want to see a change in the game world when something happened. To achieve this, let’s add an if-clause that changes the material on the component when a collision was found. We should add a new material for this purpose, which we can do from the content browser in the main scene file. Let’s change the material color to white for this one. And here we have four lights that can be turned on. Due to the way the default controls are set up, our hands only collide when they are pulled into a fist. Doesn’t matter, let’s punch those buttons on!

And here is the logic flow for turning lights on by hitting them

Part 3: Creating the game logic

Then we have only the game logic left to do.

Let’s add a variable to hold the points the user has, make it an integer, and set it to 0 in the beginning of the game.

Making a point counter

Let’s also add an array for the objects a user is supposed to hit and their order. We will only save the number of the object that is supposed to be hit, so the targets array will be of type integer. The object at index 0 of the array is the one that is supposed to be struck, and hitting any other object will lose the game.

To add the target buttons to this array we create a variable that saves the time a target was last added. This way we can check if enough time (20 seconds) passed since a target ball was added last, and if so add a new one and reset the variable to the current time.

The logic of adding a target button every 20 seconds

We want to also show the information about these targets to the player. Let’s set up logic to set the material of the of a button to the lit up version if it is the last element in the targets array, and otherwise set it to the normal material. To help with this let’s save the original materials of the objects in the initialisation function to a new array variable:

And use it to set the materials for each of the balls, the lit material if the object was the last in the targets array, and its original material otherwise.

Next let’s handle the user hitting a ball. We’ll change the collision detection path to start from the “Actor Begin Overlap”-node, and in the end of the logic when we find that a ball was hit, we’ll check if it was the correct one instead of setting its material. The ball the user was supposed to hit is in the beginning of the targets array, and if it matches we remove it from the array, increment points by one, and continue the game. If it was the wrong one, we set the boolean variable “lost” to true.

Because the player putting their hand inside a ball causes many hits, we don’t want to make them lose by hitting the same ball many times in a row. Because of this, on a successful hit we save the number of the ball that was hit into a variable, and don’t make them lose the game if they hit that ball many times.

The other condition for losing the game, being too slow, can be implemented by checking if there are too many targets the player is supposed to hit. Let’s set lost to true if there’s more than 10 targets in the target array.

After this, we’ll just have to react to the player losing the game. Let’s put all other game logic behind an if-clause that keeps the game going only if the game is not lost, and if it is turns all the balls to the lit color.

And we’re done! The last thing we can do is make the amount of points affect the speed new targets are added to the target queue, for example every `10 seconds - points*0.1`, to make the game gradually speed up until 100 points.

Here’s the final product:

We can then test the game, and invent new and stupid features for it!

--

--