Advanced VR Interactions in Unity Tutorial

Create advanced interactions and mechanics in your Unity VR app, including working with tooltips, joints, snapping and haptic feedback! By Eric Van de Kerckhove.

Leave a rating/review
Download materials
Save for later

This is an abridged version of a chapter from our new book: Unity AR & VR by Tutorials. Enjoy!

If you’ve already worked with VRTK a bit, and you feel that you’ve mastered the basics of implementing gameplay in virtual reality using VRTK, you’re ready to dive into some more exciting ways to interact with your virtual worlds.

In this tutorial, you’ll learn how to:

  • Create tooltips for objects and controllers.
  • Fix objects to your controllers.
  • Use joints to accurately pick up objects.
  • Snap objects into place.
  • Use haptic feedback.

It’s time for some VR action!

Getting Started

First, download the materials for this chapter using the Download Materials button at the top or bottom of this page.

Before diving straight into the deep end, take a moment to get familiar with the project.

Project Overview

In Unity, open the starter project for this tutorial and look at the Project window. As you can see, this project comes pre-loaded with many assets:

Here’s an overview of what’s inside:

  • OculusPlatform, OVR & OvrAvatar: The APIs for the Oculus Rift.
  • Plugins: Code libraries for the Oculus Rift.
  • Resources: Contains the settings file for Oculus Avatar.
  • Standard Assets: Unity’s standard character controllers and physics materials.
  • SteamVR: The SteamVR plugin, along with its scripts and prefabs.
  • VRTK: The Virtual Reality Toolkit plugin.

To get things started, open the Chapter 8 – Advanced Interactions scene from the Razeware\Scenes folder, and review the scene in the editor.

The scene comes with a few things already set up:

Here’s the breakdown:

  • AdvancedFullChapter8: Contains all of the basic static meshes for the scene.
  • BasicLight & ExtraLights: Various lights for the scene. ExtraLights is disabled by default.
  • RW Props: Contains the statues in the scene and is the parent GameObject for the interactables.
  • Chapter8 BGM: A simple GameObject with an Audio Source attached that plays classical music in the background. If that’s not your style, feel free to replace the music with some funky beats!

Now that you know this project inside and out, it’s time to get cracking.

Creating the VRTK Setup

By now, you may know how to prepare everything for VRTK, but to make it easier on yourself, you’re going to create a template setup which you can reuse.

SDK Manager

Create a new GameObject, name it [VRTK_SDK_MANAGER], and reset its Transform component. This will serve as the parent for the different SDK setups.

Add a VRTK_SDK Manager component to the newly created GameObject, and check any of the SDK_OCULUS_AVATAR checkboxes; the other one will get checked automatically.

Add another empty GameObject as a child of [VRTK_SDK_MANAGER], name it [VRTK_SDK_SETUPS], and reset its Transform.

Now create the following GameObjects, reset their Transform, and parent them to [VRTK_SDK_SETUPS]:

  • SteamVR
  • Oculus
  • Simulator

When you’re done, the hierarchy in the SDK Manager will look like this:

To create parented instances, drag the [CameraRig] and [SteamVR] prefabs from the SteamVR\Prefabs folder onto the SteamVR GameObject.

Drag the OVRCameraRig prefab from the OVR\Prefabs folder onto Oculus to parent the prefab. Do the same for the LocalAvatar prefab from the OvrAvatar\Content\Prefabs folder.

Select OVRCameraRig and change the value of Tracking Origin Type to Floor Level. This helps position the camera correctly.

Now drag the VRSimulatorCameraRig prefab from the VRTK\Prefabs folder onto the Simulator GameObject.

Select the three SDK GameObjects you’ve just added, and add a VRTK_SDK Setup component to all of them. Select them all separately and assign the appropriate value to Quick Select for each one:

  • SteamVR: SteamVR
  • Oculus: Oculus (Rift)
  • Simulator: Simulator

Now that you’ve added all of the SDK setups, let the SDK Manager auto populate its setup list by selecting [VRTK_SDK_MANAGER] and clicking on the Auto Populate button at the bottom.

That’s it for the SDK Manager. You’re ready to move on to the play area and controller aliases.

Play Area and Controller Aliases

As a child of [VRTK_SDK_MANAGER], create an empty GameObject. Reset its Transform and name it [VRTK_SETUP]. Create the following empty GameObjects and add them as children of [VRTK_SETUP]:

  • Play Area
  • Left Controller
  • Right Controller

When you’re done, the resulting hierarchy will look like this:

Add a VRTK_Adaptive Quality component to Play Area, set its Msaa Level to 2, and set Scale Render Viewport between 0.5 & 2.5.

This adjusts the render resolution depending on the performance; it can both upscale and downscale, so you’ll always use the optimal resolution.

Now add a VRTK_Height Adjust Teleport component to the Play Area. This serves as the base teleport method for all scenes unless specified otherwise. You can leave the variables at their defaults.

Add the following components to both Left Controller and Right Controller:

  • VRTK_Controller Events
  • VRTK_Interact Touch
  • VRTK_Interact Grab

Leave all of these components at their default values.

Add a VRTK_Pointer and a VRTK_StraightPointerRenderer component to Left Controller. This will add a straight pointer to your left controller which you can use to teleport.

Finally, click the selection button next to VRTK_Pointer’s Pointer Renderer slot, and select Left Controller.

Select VRTK_SDK_MANAGER, and hook up the controller aliases by dragging Left Controller and Right Controller to their respective slots.

Now that the SDK Manager is ready, create a new folder under Razeware named Prefabs. To turn the manager into a prefab, drag [VRTK_SDK_MANAGER] to the newly created Razeware\Prefabs folder.

Test if everything works correctly by taking a look around the scene with your preferred headset. If you find any issues, backtrack through this section and compare the steps with what you have.

The work you’ve done will prove to be a considerable time saver later on, but now it’s time to move on.

In the next section, you’ll learn how to add tooltips to GameObjects.

Object Tooltips

Tooltips are like small 3D signs you can use to label objects.

For this tutorial, you’ll be adding a name label to the armored horse, named “Knight”, in the middle of the museum. You may remember him from Unity Games by Tutorials!

To make a tooltip, you need two GameObjects: a root GameObject that will act as the target and the actual ObjectTooltip that’s provided by VRTK.

Start off by creating a container for tooltips; this helps to keep the scene nice and tidy.

Create a new GameObject, name it Object Tooltips, and reset its Transform component.

Now create the target for the knight by adding a new, empty GameObject as a child of Object Tooltips. Name it KnightTip and change its Position to (X:0, Y:1.8, Z:0).

Drag an ObjectTooltip prefab from the VRTK \ Prefabs folder onto KnightTip to make it a child.

Change the Position of ObjectTooltip to (X:1.35, Y:1.3, Z:-0.5), and change the following properties of its VRTK_Object Tooltip component:

  • Display Text: Knight
  • Font Size: 200
  • Container Size: (X:600, Y:250)
  • Line Width: 0.01
  • Font Color: Pure White (R:255, G:255, B:255)
  • Container Color: Pure Black (R:0, G:0, B:0)
  • Always Face Headset: Checked

Here’s what your settings should look like when done:

All of these, except the last one, change the visuals of the tooltip.

Always Face Headset causes the tooltip to look at the player’s headset at all times so they will never be looking at the text sideways or from the back. The reason why Draw Line From & Draw Line To isn’t being set is because you’re using a parent GameObject, and the tooltip knows to draw the line from that position to itself.

All of these changes alter the look from this tiny tooltip for ants:

To this hulking, beefy powerhouse of a tooltip:

Well at least it’s easy to see, right?

To test if it’s working correctly, play the scene and look at the knight from different angles; the tooltip should always be visible!

That’s it for object tooltips, be sure to experiment with different styles in your projects.

Next up, the controller, which can also have tooltips!

Controller Tooltips

When you start playing a new game, learning the controls can get confusing, especially with VR — a developing platform that doesn’t yet have a lot of standard controls schemes like PCs and consoles.

In this section, you’ll create a set of tooltips like this one:

Creating these is ridiculously simple, all you need to do is drag a ControllerTooltips prefab from the VRTK\Prefabs folder onto Left Controller.

This adds a bunch of pre-configured tooltips — like you added in the previous section — and the VRTK_Controller Tooltips component acts as a manager for these.

Look at the Button Text Settings on the newly added ControllerTooltips. These correspond to all possible buttons on the HTC Vive and Oculus Rift. The names don’t necessarily match that of the controller, however, here’s an overview of the HTC Vive controller and an Oculus Touch controller:

  • Trigger: Hair Trigger on Vive, Trigger on Rift
  • Grip: Grip on Vive, Grip on Rift
  • Touchpad: Touchpad on Vive, Analog Stick on Rift
  • Button One: N/A on Vive, Bottom Button on Rift
  • Button Two: Menu Button on Vive, Top Button on Rift
  • Start Menu: N/A on Vive, Start Button on Rift

Notice the last three differ between the Vive and the Rift. In this case, you’ll be targeting the HTC Vive setup as an example. If you’re using an Oculus Rift, switch around the Button Two and Start Menu Text.

Change the Button Text Settings to the following:

  • Trigger Text: Teleport Pointer
  • Grip Text: Grab
  • Touchpad Text: Shoot
  • Button One Text: (empty)
  • Button Two Text: Menu
  • Start Menu Text: (empty)

The Object Tooltips are hidden for all empty text fields. That means, if you only want to label just one or two inputs, that’s not a problem!

Now that tooltips are done, save the scene so you don’t lose any work. Then, run the scene, look at your controller, and you’ll see the tooltips spread all around it.

Adding tooltips was fun, right?

In the next sections, you’ll explore how to add some specific functionality to pick up objects.

Fixing Objects to your Hands

In some cases, you might want an object to be fixed to a controller. Or you might want to replace an object with another one after you grab it. Think guns, swords and boxing gloves, for example. You can even automatically grab a GameObject or cloned prefab right at the start of the scene.

For now, though, you’ll start off with creating a basic example: a tank figurine that attaches to your controller permanently once you grab it. This is what happens when you spill a bottle of glue on your tank!

Simple Fixing

Create a new empty GameObject, name it TankFigure, and set its Position to (X:8, Y:1.115, Z:3.5). Then, drag Tank from the Razeware\Models folder and drop it onto TankFigure, making Tank a child of TankFigure.

Change the newly added model’s Scale to (X:0.21, Y:0.21, Z:0.21), and drag TankFigure onto RW Props to parent it.

When you’re done, the new hierarchy will look like this:

Create a new folder inside the Razeware\Prefabs folder and name it Grab. Drag the TankFigure onto the new folder to turn it into a prefab.

You’ll now have a little tank sitting on the table.

This is cool, but you need a way to interact with it.

The easiest and fastest way to add the components you’ll need for this interaction is to use VRTK’s interactable setup wizard.

With TankFigure still selected, open the setup by selecting Window ▸ VRTK ▸ Setup Interactable Object in the top menu.

Leave everything at their default values and press the Setup selected object(s) button at the bottom.

Close the setup window and remove the VRTK_Interact Haptics component from TankFigure.

Under the Grab Options in the VRTK_Interactable Object, set Valid Drop to No Drop; this setting makes it so the player can’t drop the tank after grabbing it.

Before testing if it all works, add a Box Collider component to TankFigure, set its Center to (X:0, Y:0.06, Z:0) and its Size to (X:0.3, Y:0.23, Z:0.3).

This surrounds the small tank. To test it out, dive into VR and try to pick up the sticky tank.

Note: If you can’t find the figurine anywhere, you may have skipped this step, which causes the tank to drop through the floor.

No matter how hard to try, this tank won’t come off! If you don’t want your players to drop something important, or if you want to attach silly stuff to their controllers, this works out nicely.

Next, you’re going to add a pistol that replaces the controller.

Custom Fixing

Add a new empty GameObject to the scene as a parent of RW Props, and name it Pistol. Change its Position to (X:8, Y:1.15, Z:4.5), and drag the Pistol model from the Razeware \ Models folder onto Pistol to create a child.

At the moment, the pistol is a tad too big and not positioned correctly. To fix this, change its Position to (X:0, Y:0, Z:0), its Rotation to (X:-90, Y:90, Z:-90), and its Scale to (X:23, Y:23, Z:23).

There, all better:

Select the Pistol parent and open the VRTK setup wizard (Window ▸ VRTK ▸ Setup Interactable Object). Leave everything at their default values and hit the Setup selected object(s) button.

Close the window and remove the VRTK_Interact Haptics component from Pistol.

Add a Box Collider and set its Center and Size to (X:0, Y:-0.018, Z:0.065) and (X:0.11, Y:0.24, Z:0.37) respectively.

Change Valid Drop on the VRTK_Interactable Object component to No Drop. Right now, it behaves exactly like the tank. To hide the controller when the pistol is grabbed, add a VRTK_Interact Controller Appearance component to the Pistol, and enable the Hide Controller On Grab checkbox.

Test out the scene and see if the controller disappears when you grab the pistol. Well, the controller disappears, but you’re stuck with a gun that’s at an awkward angle:

The reason for this is because GameObjects are attached to your controller at the angle you started grabbing them. To fix this, you’ll need to add a snap handle so the position and rotation of the pistol are always the same relative to the controller.

To create the snap handle, create a new empty GameObject as a child of the parent Pistol GameObject and name it SnapHandle.

Set its Position to (X:0, Y:0.015, Z:0.015) and its Rotation to (X:75, Y:0, Z:0); this will orient the handle like this:

Notice how the handle is rotated 75 degrees on the x-axis? This is important to remember if you want to position snap handles correctly for objects with a grip like guns, swords and other objects.

Here’s how the snap handle will affect how the controller grabs the pistol:

Now drag the SnapHandle to the Right and Left Snap Handle slots in Pistol’s VRTK_Child Of Controller Grab Attach component.

Make the Pistol into a prefab by dragging it into the Razeware\Prefabs\Grab folder, then play the scene again.

The pistol is now aligned to your hand in a more natural position and will follow your hand rotation. The controller itself is also hidden.

This what the developers of Job Simulator have dubbed Tomato presence:

Note: Tomato presence is the concept that hand presence can be maintained using a stand-in object in VR and that the brain will intuitively accept it.

Before moving on to the next section, there’s one more related mechanic you need to work out: automatically grabbing a GameObject.

Auto Grabbing

To automatically grab an object at the start of the scene, you could write a script, but as it turns out, VRTK has a handy component you can add to a controller alias called VRTK_Object Auto Grab. This can automatically grab any interactable objects from the scene or an instantiated prefab.

Select the Right Controller under [VRTK_SDK_MANAGER] \ [VRTK_SETUP], and add a VRTK_Object Auto Grab component to it.

Then, drag the Pistol to the Object To Grab field.

That’s it! Try the scene again, and the pistol will automagically replace your right controller.

Hand Attachments with Joints

There are other methods of attaching objects to controllers besides just parenting them.

If you played around in the scene a bit, you might have noticed you can move the objects right through other objects as soon as you’re holding them. It’s almost as if you’re holding a ghost object. Spooky!

This is because the rigidbody gets set to kinematic if you’re using the VRTK_Child Of Controller Grab Attach component.

For the next object, you’ll use a fixed joint to attach the object to the controller, giving it some realistic behavior.

Create a new empty GameObject as a child of RW Props. Name it VikingDoll, and set its Position and Rotation to (X:8, Y:1.04, Z:5.5) and (X:0, Y:-90, Z:0) respectively.

Drag the Viking model from the Razeware\Models folder onto VikingDoll in the Hierarchy to parent an instance of the model, and set its Scale to (X:0.16, Y:0.16, Z:0.16).

Now, to add a basic VRTK setup.

Select VikingDoll and open the VRTK setup wizard (Window ▸ VRTK ▸ Setup Interactable Object).

Leave everything at their default values except for Grab Attach Mechanic; set this to Fixed Joint and hit the Setup selected object(s) button.

Close the window and remove the VRTK_Interact Haptics component and enable Precision Grab on the VRTK_Fixed Joint Grab Attach component.

Add a Box Collider to the VikingDoll, and set the Center to (X:0, Y:0.2, Z:0.02) and the Size to (X:0.2, Y:0.4, Z:0.18).

That’s all you have to change to get fixed joint attaching working!

The precision grab allows you to grab the object at the particular point where the controller is colliding with the object.

Try the scene again and grab the viking doll. If you attempt to move the doll through the table, you’ll “lose grip”, and you’ll drop the doll.

The joint breaks because the force between the controller and the doll is too great. The controller can move around freely, but the doll can’t enter solid objects, so it’s as if you pull a string from both ends until it snaps.

The force needed to snap this imaginary string is set by the Break Force field on the VRTK_Fixed Joint Grab Attach component.

If you don’t want to break the link between the controller and the object at all, but still want to avoid objects going through each other, there’s also the Track Object grab attach mechanic.

This attachment method applies the velocity of the controller to the grabbed object. It’s less accurate than the methods previously discussed, but it may help you in certain scenarios.

Object Snapping

You can create a lot of different behaviors by snapping objects together. Snapping objects together means that you can insert one object into another object. For example, a USB stick in a USB port, a wheel on a car, and so on.

In this section, you’ll create a battery and a battery holder, which provides the museum with some extra juice to power an extra set of lights.

First, create the battery:

Add a new empty GameObject to the scene, name it Battery, and set its Position and Rotation to (X:8, Y:1.08, Z:8) and (X:0, Y:-120, Z:0) respectively.

Drag the Battery model from the Razeware\Models folder onto the GameObject you just created, so it has some visuals.

The Battery model is composed of two parts: the battery and the battery holder:

Separate BatteryHolder by dragging it between Object Tooltips and Battery in the Hierarchy. You’ll be asked to break the prefab instance. When prompted, select OK.

To make things less confusing moving on, rename it to BatteryHolderModel, and reset its Position to (X:0, Y:0, Z:0) so it’s out of the way. To add basic functionality to the battery, select the Battery parent GameObject and open the Interactable Object wizard.

Set the Touch Highlight Color to a solid yellow (R:255, G:255, B:0), uncheck Add Haptics, and click the Setup selected object(s) button.

Add a Capsule Collider component to the Battery. Set its Radius to 0.08, its Height to 0.4, and enable Is Trigger. Also, set the Direction to X-Axis.

Finally, drag the parent Battery GameObject to the Razeware\Prefabs\Grab folder to turn it into a prefab.

You can now pick up the battery and throw it around, but there’s still nowhere to plug it in. This is where the BatteryHolder comes into play!

Create a new empty GameObject, name it BatteryHolder, and set its Position to (X:0, Y:1.35, Z:9.2).

Drag BatteryHolderModel onto BatteryHolder to parent it, and set its Position and Rotation to (X:0, Y:0, Z:0) and (X:-90, Y:180, Z:0) respectively. The result will look like this:

To allow objects to accept other objects to snap onto them, you need a Snap Drop Zone — this component filters out the objects that can be attached to it and handles the movement, rotation and scale transition.

Add a VRTK_Snap Drop Zone component to the BatteryHolder. Assign the Battery prefab to the Highlight Object Prefab field, and set Snap Duration to 0.2. Set the Highlight Color to a bright green color (X:40, Y:255, Z:0).

You’ll now see a pink transparent copy of the battery inside the holder:

Right now, most of the snap drop zone settings are ready, except it won’t accept any objects as-is. To add valid objects, you need to add a Policy List; this is a handy way of filtering based on several requirements. It can filter by tag, script or layer, and can even accept or reject everything if you wish.

Add a VRTK_Policy List component to the BatteryHolder, set its Operation to Include, and fill in Battery in Element 0 of the list.

Now all of the objects with the Battery tag are allowed to snap into this object. Assign the Battery tag to the Battery by selecting the Battery GameObject and choosing Battery from the Tag dropdown. Click the Apply button afterward, so the prefab gets saved too.

Select BatteryHolder and drag the VRTK_Policy List component onto the VRTK_Snap Drop Zone component’s Valid Object List Policy field to set up the reference to the policy list that should be used for objects allowed to be snapped into place on the battery holder.

The drop zone needs a collider and a rigidbody so it can detect when an object enters in range. Select BatteryHolder and add a Rigidbody and a Capsule Collider component. Disable the gravity on the rigidbody and make it kinematic: you don’t want it falling on the floor.

Set the Radius on the collider to 0.1, set Height to 0.5, and change the Direction to X-Axis.

There’s one final part missing to complete the BatteryHolder: you need a way of making stuff happen when the battery is put inside the batter holder. For this, you’ll need another component: a Snap Drop Zone Unity Events. This lets you visually link the events.

Add a VRTK_Snap Drop Zone_Unity Events component to BatteryHolder, and add a new event to both On Object Snapped To Drop Zone and On Object Unsnapped From Drop Zone. Drag ExtraLights to both Object slots and select GameObject ▸ SetActive. For the snap event, check the box so it’ll become active.

Create a new folder in the Razeware\Prefabs folder named DropZone. Drag the BatteryHolder to the newly created folder to turn BatteryHolder into a prefab.

Everything is ready for snapping now. Run the scene and try to pick up the battery; teleport to the battery holder and snap the battery into place.

If everything works correctly, you’ll see an extra set of lights switch on.

Haptic Feedback

There are a few ways to add haptic feedback (or vibration) to interactions, such as adding a component that handles the haptics.

Add a new empty GameObject to the Hierarchy, name it BombToy, and parent it to RW Props. Set its Position to (X:8, Y:1.11, Z:6.5), and drag the Bomb model from the Razeware\Models folder onto the newly made GameObject to give it some visuals.

Reset the Bomb Position to (X:0, Y:0, Z:0); and to size it down a bit, set its scale to (X:18.5, Y:18.5, Z:18.5). You’ll now have a bomb sitting on the table:

Don’t worry; it’s safe!

Select BombToy and open the VRTK setup wizard (via Window ▸ VRTK); leave everything at their default values and click the Setup selected object(s) button.

Add a Sphere Collider component to the BombToy with a Radius of 0.105 to prevent it from dropping through the floor.

The component you’re interested in is VRTK_Interact Haptics. Until now, you’ve removed this as it wasn’t needed for the other objects.

To get it to work, you’ll need to tweak its variables.

Set Strength On Touch to 0.2, Duration On Touch to 0.1 and Interval On Touch to 0.1 as well in the Haptics On Touch section.

This gives a light and short vibration when you touch the bomb with your controller.

To make it vibrate when you grab it, change the following:

Set Strength On Grab to 0.4, Duration On Grab to 0.2 and Interval On Grab to 0.05 as well in the Haptics On Grab section. This causes the controller to vibrate a bit more violently, letting you know you’ve successfully grabbed the object.

Drag the BombToy to the Razeware\Prefabs\Grab folder to turn it into a prefab. Test if the bomb works as intended by running the scene then touching and grabbing the bomb.

You can also create more interesting effects by creating your own scripts to handle the haptics. To demonstrate, you’ll add a pulse-effect to the battery while you hold it.

Create a new C# script in the Razeware\Scripts folder, name it PulseOnHold, and open it in your code editor.

Remove the Start() and Update() methods, and add the following line below the other using statements:

using VRTK;

Now replace this line:

public class PulseOnHold : MonoBehaviour {

With this one:

public class PulseOnHold : VRTK_InteractableObject {

This causes the script to derive from InteractableObject, which includes some essential functionality.

Now, add the following variables below the class declaration:

public float pulseInterval = 2f; // 1
public float pulseDuration = .2f; // 2

private VRTK_ControllerReference controllerReference; // 3
private IEnumerator pulseRoutine; // 4

Here’s what they’re used for:

  1. The time between every pulse.
  2. The amount of time the pulse lasts.
  3. A reference to the controller that receives the vibration.
  4. A cached coroutine for correctly starting and stopping the haptic feedback.

Add the following coroutine to do the vibrating:

IEnumerator DoPulsing()
    while (gameObject.activeSelf)
        VRTK_ControllerHaptics.TriggerHapticPulse(controllerReference, 0.5f, pulseDuration, 0.01f);
        yield return new WaitForSeconds(pulseInterval);

This keeps vibrating the controller at the specified interval until the GameObject gets deactivated or the coroutine is stopped.

Next, add the following methods:

private void OnEnable() // 1
    pulseRoutine = DoPulsing();

public override void Grabbed(VRTK_InteractGrab grabbingObject) // 2
    controllerReference =

public override void Ungrabbed(VRTK_InteractGrab grabbingObject) // 3
    controllerReference = null;

Here’s the breakdown:

  1. Call the base class OnEnable() method and cache a reference to the DoPulsing() coroutine.
  2. This method gets called when a controller grabs the GameObject to which this script is attached. The grabbingObject is stored as the controller, and the pulse routine is started.
  3. This method gets called when a controller releases the GameObject to which this script is attached. The controller is cleared, and the pulse routine is stopped.

Save the script and return to the Unity editor.

Add the Pulse On Hold component to the Battery, and remove the VRTK_Interactable Object component. Your custom component replaces its functionality.

Next, you’ll take a look at the Pulse On Hold component.

Change the Touch Highlight Color to Pure Yellow (R:255, G:255, B:0) and check Is Grabbable.

Don’t forget to update the base battery prefab by clicking Apply on the Battery GameObject in the Hierarchy.

That’s it! Run the scene and grab the battery. You should feel a pulse as long as you’ve got the battery in your hand. Can you feel the force flow with all that energy?

Where to Go From Here?

You can download the final project from this tutorial using the “Download Materials” button at the top or bottom of this page.

Well done! You now know how to add exciting mechanics to your own VR games.

If you had trouble following along, or you want to compare your project to the sample one, you can find the final project included with this tutorial’s resources files.

Here’s a quick recap of what you did. In this tutorial, you learned how to:

  • Create tooltips for objects and controllers.
  • Fix objects to your controllers.
  • Use joints to accurately pick up objects.
  • Snap objects into place.
  • Use haptic feedback.

If you have any questions or comments, please leave them below!