HTC Vive Tutorial for Unity

Learn how to use the HTC Vive with Unity! Grab and throw objects, shoot lasers and teleport around an area. By Eric Van de Kerckhove.

4.4 (19) · 1 Review

Download materials
Save for later
Share
You are currently viewing page 3 of 5 of this article. Click here to view the first page.

Using Actions

With the actions created and bound to hardware inputs, you can now finally use these in your game!

Start with selecting the Pose Actions for the controllers; this links the physical controllers’ position and rotation to the virtual ones.
Expand [CameraRig] in the Hierarchy and select Controller (left).

Change its Pose Action to \actions\default\in\SkeletonLeftHand to link it to the left controller.

Now do the same with Controller (right), but change its Pose Action to \actions\default\in\SkeletonRightHand instead.

Next, create a new C# script in RW \ Scripts, name it ActionsTest and open it in your favorite code editor.

Remove the Start() method and add the following to the top of the file:

using Valve.VR;

This references the namespace needed to access the VR input classes.

Next, add the following right above Update():

public SteamVR_Input_Sources handType; // 1
public SteamVR_Action_Boolean teleportAction; // 2
public SteamVR_Action_Boolean grabAction; // 3

With this code, you made:

  1. The type of hand(s) to poll for input. These are either All, Left or Right.
  2. Reference to the Teleport action.
  3. Reference to the Grab action.

Now, add the following methods right below Update():

public bool GetTeleportDown() // 1
{
    return teleportAction.GetStateDown(handType);
}

public bool GetGrab() // 2
{
    return grabAction.GetState(handType);
}

Here’s what these are for:

  1. Poll if the Teleport action was just activated and return true if this is the case.
  2. Poll if the Grab action is currently activated.

Finally, add the following if-statements to Update():

if (GetTeleportDown())
{
    print("Teleport " + handType);
}

if (GetGrab())
{
    print("Grab " + handType);
}

These statements check the methods you created and print a message to the console when these return true.

You’re ready to test the sript. Save it and return to the Unity editor.

Select both Controller GameObjects and add an Actions Test component to both by clicking Add Component, typing “Act” and selecting the top option.

Open the Teleport Action drop-down and change its value to \actions\default\in\Teleport. Now, do the same for Grab Action and change it to \actions\default\in\Grab.

Finally, select only Controller (left) and change its Hand Type to Left Hand. Do the same for Controller (right), but choose Right Hand this time.

Run the game again, take both controllers in your hands, press some buttons and squeeze the triggers. Now look at the Console line at the bottom of the screen:

Notice, every action gets registered in the console.

That’s it for basic input config. Now you have the power to manipulate the virtual world at your fingertips — literally!

Using The Controllers With Physics Objects

VR affords users many opportunities that are not possible in the real world, including picking objects up, examining them and throwing them around without having to clean up afterward.

You can create this carefree virtual experience by employing some trigger colliders and doing a bit of scripting.

Select both controllers in the Hierarchy and add a Rigidbody component to them. (Add Component > Physics > Rigidbody)

Check the Is Kinematic checkbox and uncheck Use Gravity:

Now, add a Box Collider (Add Component > Physics > Box Collider) to both controllers and check Is Trigger.

The default collider is huge, so you’ll need to resize and reposition it. Set Center to (X:0, Y:-0.04, Z:0.02) and Size to (X:0.14, Y:0.07, Z:0.05). In this case, you require these kinds of precise values because even a hundredth of a unit affects where the collider ends up.

Run the game again. Select a controller in the Hierarchy and pick up the real controller. Look at the Scene view and focus on the controller you’re holding (press F). The collider goes right over the top part of the controller, which is the part you use to pick up objects.

ControllerColliderScene

Without a script, this collider is little more than a useless cube. Create a new C# script in RW \ Scripts, name it ControllerGrabObject and open it.

Add this to the top of the script:

using Valve.VR;

Like the previous script, this allows you easy access to the SteamVR classes.
Now, remove the Start() method and add this familiar code in its place:

public SteamVR_Input_Sources handType;
public SteamVR_Behaviour_Pose controllerPose;
public SteamVR_Action_Boolean grabAction;

This is the same code you used for the input test script. It stores references to the hand type and the actions.
Add these variables below the ones you just added:

private GameObject collidingObject; // 1
private GameObject objectInHand; // 2

Each variable has a purpose:

  1. Stores the GameObject that the trigger is currently colliding with, so you have the ability to grab the object.
  2. Serves as a reference to the GameObject that the player is currently grabbing.

Next, add this method above Update():

private void SetCollidingObject(Collider col)
{
    // 1
    if (collidingObject || !col.GetComponent<Rigidbody>())
    {
        return;
    }
    // 2
    collidingObject = col.gameObject;
}

This method accepts a collider as a parameter and uses its GameObject as the collidingObject for grabbing and releasing. Moreover, it:

  1. Doesn’t make the GameObject a potential grab target if the player is already holding something or the object has no rigidbody.
  2. Assigns the object as a potential grab target.

Add these trigger methods:

// 1
public void OnTriggerEnter(Collider other)
{
    SetCollidingObject(other);
}

// 2
public void OnTriggerStay(Collider other)
{
    SetCollidingObject(other);
}

// 3
public void OnTriggerExit(Collider other)
{
    if (!collidingObject)
    {
        return;
    }

    collidingObject = null;
}

These methods handle what should happen when the trigger collider enters and exits another collider.

  1. When the trigger collider enters another, this sets up the other collider as a potential grab target.
  2. Similar to section one (// 1), but different because it ensures that the target is set when the player holds a controller over an object for a while. Without this, the collision may fail or become buggy.
  3. When the collider exits an object, abandoning an ungrabbed target, this code removes its target by setting it to null.

Next, you’ll add some code to grab an object below OnTriggerExit():

private void GrabObject()
{
    // 1
    objectInHand = collidingObject;
    collidingObject = null;
    // 2
    var joint = AddFixedJoint();
    joint.connectedBody = objectInHand.GetComponent<Rigidbody>();
}

// 3
private FixedJoint AddFixedJoint()
{
    FixedJoint fx = gameObject.AddComponent<FixedJoint>();
    fx.breakForce = 20000;
    fx.breakTorque = 20000;
    return fx;
}

In here, you:

  1. Move the colliding GameObject into the player’s hand and remove it from the collidingObject variable.
  2. Add a new joint that connects the controller to the object using the AddFixedJoint() method below.
  3. Make a new fixed joint, add it to the controller, and then set it up so it doesn’t break easily. Finally, you return it.

What can be grabbed must be released. This next block handles releasing the object:

private void ReleaseObject()
{
    // 1
    if (GetComponent<FixedJoint>())
    {
        // 2
        GetComponent<FixedJoint>().connectedBody = null;
        Destroy(GetComponent<FixedJoint>());
        // 3
        objectInHand.GetComponent<Rigidbody>().velocity = controllerPose.GetVelocity();
        objectInHand.GetComponent<Rigidbody>().angularVelocity = controllerPose.GetAngularVelocity();

    }
    // 4
    objectInHand = null;
}

This code removes the grabbed object’s fixed joint and controls its speed and rotation when the player tosses it away. The controller’s velocity is vital here. Without using it, the discarded object would drop straight down no matter how perfect your throw might be. Trust me, it doesn’t feel right. :]

Section-by-section breakdown:

  1. Make sure there’s a fixed joint attached to the controller.
  2. Remove the connection to the object held by the joint and destroy the joint.
  3. Add the speed and rotation of the controller when the player releases the object, so the result is a realistic arc.
  4. Remove the reference to the formerly attached object.

Finally, add this inside Update() to handle the controller input:

// 1
if (grabAction.GetLastStateDown(handType))
{
    if (collidingObject)
    {
        GrabObject();
    }
}

// 2
if (grabAction.GetLastStateUp(handType))
{
    if (objectInHand)
    {
        ReleaseObject();
    }
}
  1. When the player triggers the Grab action, grab the object.
  2. If the player releases the input linked to the Grab action and there’s an object attached to the controller, this releases it.

I bet you can’t wait to try this out! Save the script and return to the editor.

Select both controllers in the Hierarchy and add a Controller Grab Object component to each.

With both controllers still selected, set the Grab Action to \actions\default\in\Grab. Next, select only Controller (left), set its Hand Type to Left Hand and drag the Steam VR_Behaviour_Pose component onto the Controller Pose slot.

Now do the same for the right controller, but use Right Hand instead.

Time to have some fun! Get your controllers ready, start the game and put on the headset. Pick up and toss around some cubes and balls using the hair trigger or the grip button. You can even juggle with a bit of practice.

GrabbingPlay

You have to hand it to yourself, you’re pretty awesome right now. However, I think you can make your VR experience even cooler.