December 9, 2022
Note: The add-on provides comprehensive documentation as well. You can find it in Unity in path: MindPort → VR Builder → Add-ons → TrackAndMeasure → Documentation
In this VR Builder tutorial we will learn how to use the features of the Track & Measure add-on for VR Builder. In doing so, we will create a simple ball game in VR where the player has to throw a ball into different slots in a certain amount of time. Depending on which slot is hit, the player will receive or lose points.
After following the tutorial, you will have a good understanding of the Track & Measure add-on features to enhance your own VR content in Unity. In doing so, we will cover:
This Unity scene has been assembled with Unity primitives and consists of a gaming machine with a ball and container, three slots to hit and a score board.
You can download the exact same Unity scene, or create your own scene and process. In our scene, all static scene elements are grouped under the StaticEnvironment game object. All objects needed for building the process are on the root of the Hierarchy for convenience.
Now we want to create a ball game in VR with the following rules:
Also it is important to note that:
Now we start creating the following game flow in virtual reality:
The final workflow looks like this:
For more help on using the Process Editor, see the tutorial on creating the process for your VR application.
First we want to display user progress in VR. Therefore, we need to capture two values: the time remaining and the player's score.
Track & Measure provides a way to handle variables in the process editor: Data property components can be added to process scene objects and store values in them. These values can be read or written by referencing the process scene object in the Step Inspector.
We recommend creating a process scene object to store each property. Let's start by creating two empty game objects, one named Timer and the other named Score. For convenience, we'll group them under one empty object called Data Properties.
We could simply drag these game objects into the process and click the tried and true Fix it button. This time, however, we'll add the components manually to better understand how the system works. To start, we'll select the Score game object and add the Number Data Property to it.
As we can see, this also adds a Process Scene Object component. The Number Data Property stores a single number - what a surprise! It's basically a floating point number, but let’s not worry about that for now. Now let's add a Timer Property to the Timer game object.
Adding the Timer Property automatically creates a Process Scene Object and a Number Data Property. The Number Data Property stores the actual timer value. The job of the Timer Property is simply to adjust this value either up or down, which means you can use the timer value as you would any other Number data Property.
Then we can complete the process by displaying the time and score in the track display.
Track & Measure provides Data Display prefabs that work out of the box for displaying data properties in TextMeshPro objects. You can find the prefabs in the Assets/MindPort/VR Builder/Add-ons/Track and Measure/Prefabs/Data Displays folder. We need a Number Data Display for the score and a Time Data Display for the timer. They both read Number Data Properties, but the latter converts the value to a time format instead of a numeric format.
Now drag the two displays directly in front of the Monitor object. The result looks like this:
For the displays to work, they need a reference to the appropriate data property. Therefore we drag the Timer object to the Data Property field on the Time display. Accordingly, we drag the Score object to the Data Property field on the Number display.
Now the two displays will show the corresponding values (time and points). We will take care of formatting and customizing the displays in section 9 of this tutorial.
In order for the user to grab the ball, we need the Grab Object condition. Therefore, open the Step Inspector, add a Grab Object condition, and reference the ball. For more information on using the Step Inspector, see the tutorial on creating steps for your VR application.
As soon as the user grabs the ball the timer starts ticking and starts the countdown. Therefore, this step requires two actions to be performed: defining the value of the timer and starting the countdown.
To set the value of the timer, we add the Set Number behavior to the Start Timer step: Step Inspector > Behaviors > Track and Measure > Set Number. The Set Number behavior sets a number property to a specific value. Since the timer stores the time in a number property, we can use it to set the start time to any value.
To set the value for the timer, drag the Timer object into the Data Property field and set a suitable time. One minute sounds good, so we enter 60 in the value field. Note that the time in the Number Data property is always stored in seconds, however, you can display the time in any format you want.
Next we want to tell the timer when to start ticking. This requires the Start Timer behavior, which can be found under Track and Measure > Start Timer, and reference the Timer object again. Then check the Is Countdown box - this way the timer will count down and stop at zero instead of running up.
Now the timer should work - if we press Play and grab the ball, we will see the time counting down on the screen.
After the timer starts ticking, the user directly proceeds to the Play step without any condition being met. The Play step is where most of the actions take place in the game.
As soon as the user repeats this step again and again, e.g. by throwing the ball several times, the ball should always move to the starting position. This requires the Move Object behavior, which moves the Ball object to the BallSpawnPoint position.
Now it’s time to set the different transitions of this step for each Point Increase, Point Decrease and Game Over. We’ll construct the general structure in the Process Editor first, then complete them in the Step Inspector.
This transition checks if the time has expired and results in a Game Over step. You will notice that there is no specific Time expired condition - but there is no need to, since the time is stored in a number property. We can use a Number compare condition, which you find under Add Condition > Track and Measure > Compare Numbers, and check if the value of the timer's data property is zero.
We know that a timer stops when it reaches zero - this ensures that this will work. Note that this function is much more powerful than a Time finished condition, because you can use it to check time thresholds and even compare the time with another data property.
Next we need to check if the ball is in
If the ball is in the center slot, this triggers the Increase point step. Accordingly, if the ball is in the right or the left slot, this triggers the Decrease Point step. The workflow looks like this:
To display these three possible results we require three new transitions and the Move Object in Collider condition for each of them. Then reference the ball and the three colliders for the center, right, and left slots, respectively. This is the result:
Finally, we should perhaps add a little fail-safe feature. If the ball has not reached a hole after a certain time, for example because it has been lost, the player loses points and the ball is reset. For this we simply add a timeout condition that leads to the Decrease Point step after about 10 seconds.
Now, let’s loop the Point Increase step and Point Decrease step back to the Play step - after scoring once, the ball will reset to its initial position and the player is able to throw the ball again. The workflow looks like this:
Now, when you press Play, you should be able to throw the ball in VR and interact with the various slots. Please mind that no score will be calculated. However, you should get a new ball either every time the ball falls into a slot or after 10 seconds of inactivity.
Now that we have defined the workflow of our VR game, it’s time to work on the score! Every time the user loses or gains a point, the score should be updated accordingly. This requires an Update Score behavior.
In order for the score to increase when the user successfully throws the ball into the center slot, we need to add the Update Score behavior to the Increase Score step. Then, reference the Score data property you created at the beginning to the Data property and set the number of points you want to award for a correct throw. In this example, we will go with 100 points. Add this value to the Increase Score field.
Now the score is updated and shown on the display.
It is very easy to add other feedback, such as a sound or the display of a floating number to indicate the increased score.
A game object with a feedback property can be customized by adding or removing components to give feedback about the increase or decrease of the score. We will learn more about this in section 10 of this tutorial.
For now, VR Builder includes pre-built feedback provider prefabs: these can be found in the Assets/MindPort/VR Builder/Add-ons/Track and Measure/Prefabs/Score Feedback folder. They are named Incremental Score Negative Feedback Provider and Incremental Score Positive Feedback Provider, respectively. Drag the two prefabs into the scene.
These two prefabs each play a negative and a positive sound and have a floating number that moves up or down. Since we want to increase the score, we drag the Positive Feedback Provider from the scene to the Feedback property field in the step.
This prefab provides positional feedback: this means that the floating number appears and sound plays at a specific position. To add positional feedback when the player scores a point, select the Increase Score step and drag the empty ScoreFeedbackPosition object into the Feedback position provider field.
Now do the same with the step of Decrease Score. The only difference is that instead of increasing the player's score by 100 points, we decrease it by 50 points and use negative feedback. The final result looks like this:
Now when we press Play, everything works except that the process ends abruptly when the timer runs out. To indicate that the timer has expired, we add a visual cue, confetti rain, to the Game Over step. To implement confetti, go to Step Inspector > Behaviors > Add Behavior > Guidance > Spawn Confetti.
The game is fully functional and the data displays show the correct information. However, we want to format the display a little differently; we are dealing with integer results, so we don't need decimals. Likewise, the timer runs in seconds, so we may want to add fractions of seconds to increase the urgency.
We can change the formatting in the Data Display prefabs. Let's start with the score display. In the Text field of the Number Display component we see the following:
Even though it looks a bit confusing when we hover over the Text label, we will understand that what we see here is just the name of the game object, a colon and the value with two decimal places.
We can change Data Display prefab settings to the following:
This removes the decimal digits. We added Score so the formatting won't change if the game object is renamed for some reason. Let's also take a look at the Time Display. The Text field looks provides the following information:
We reformat the text and insert decimals after the seconds.
You can find more information on how to format time values in the Standard TimeSpan format strings documentation from Microsoft. Moreover, we can also change the font type or text color, e.g. to orange:
This little project is ready - now it's time to press Play and start gaming. In addition, there are more possibilities for improvement, some of which are listed in the next section.
VR Builder provides pre-built objects for scoring feedback. Users can easily customize them and create their own logic. Let's take a look at one of the provided prefabs:
In addition to the Process Scene Object and Score Feedback Property, there are two more components on this object: Floating Text Score Feedback and Audio Score Feedback. Floating Text Score Feedback displays continuous text, whereas Audio Score Feedback plays audio. WOW!
A user can easily create a similar object and combine and customize the Score Feedback components as desired. These can be further customized by changing the prefabs for the floating text and the audio source, for example, replacing the latter with a 2D audio source if positional sound is not desired.
To create a score feedback component, simply implement the IScoreFeedbackProvider interface in a component and then insert the desired logic in the TriggerFeedback method. For example, a component that logs a change in score would look like the following:
When we add this component to our feedback providers, a log entry like this is created when the Update Score behavior is invoked.
We can improve the game experience by letting the player know how well they did at the end of the game. For this purpose, we can use some conditions of Compare Numbers to set thresholds that lead to different behaviors, for example with a text-to-speech comment. It should be noted that the conditions are evaluated one after the other and the first available condition triggers, so we have to arrange them accordingly.
We could apply a penalty to the final score if the player loses at least one ball (i.e. triggers the timeout condition at least once). For this purpose, we can create a new Boolean data property (a true/false variable), as we did for Score and Timer, and call it LostBall. This will record whether the player lost a ball during the game, and if so, the penalty will be applied at the end of the game.
When the timeout condition is triggered, we can add a new step with a Set Boolean behavior that sets this data property to True.
Then, before Game Over, we can add a step called Check Penalty: This step uses a Compare Booleans condition to check if the property is True (i.e. a ball was lost), and if so, an additional step is played that deducts more points.
It is easy to change the game so that the player gains more seconds with a correct shot and/or loses some with a wrong shot. Since the time is stored in a number property, it can also be changed by using the Update Score behavior. Simply use Update Score for the timer and specify the number of seconds to add or subtract.
In this VR Builder tutorial, you learned how to create VR games in Unity using the Track & Measure add-on. Now it's your turn to play with the gamification features and create your own game in VR. If you haven't already, download the Track & Measure add-on!