How To Implement Walking in Unity SteamVR

There is now a new updated tutorial based on this one, so still read this one, but make sure to check out the new one for bug fixes, jumping code, and general improvement. Also, the latest version of the code and an example scene are included in the VR instincts plugin on GitHub.

One of the most basic game mechanics you want in your game is the ability to walk. I know that people claim that walking mechanics in VR games cause nausea, but they are also the most immersive form of movement. Could you imagine playing a game like Halo or Call of Duty where you have to teleport every step? No, it would be a terrible experience. But that’s my titanium stomach talking.

So let’s get to it! To start off, as always we are going to set up our steamVR bindings. You are going to want to create one action to store a Vector2 named MovementAxis, this is the one we use to get input from our touchpad.

Now we set up our scene, add a Rigidbody and capsule collider to your [cameraRig] component, make sure that you constrain all rotation on the rigidbody so you don’t find yourself falling over. For the capsule collider all you need to set is the radius since all the other values are controlled by our code, I set mine to 0.1.

Now we can start to code. Create a new script called movement and add it to your [CameraRig] component. Here Is the code I used:

using Valve.VR;
public class Movement : MonoBehaviour
{
private Vector2 trackpad;
private float Direction;
private Vector3 moveDirection;


public SteamVR_Input_Sources Hand;//Set Hand To Get Input From
public float speed;
public GameObject Head;
public CapsuleCollider Collider;
public GameObject AxisHand;//Hand Controller GameObject
public float Deadzone;//the Deadzone of the trackpad. used to prevent unwanted walking.
// Start is called before the first frame update

void Update()
{
//Set size and position of the capsule collider so it maches our head.
Collider.height = Head.transform.localPosition.y;
Collider.center = new Vector3(Head.transform.localPosition.x, Head.transform.localPosition.y / 2, Head.transform.localPosition.z);

moveDirection = Quaternion.AngleAxis(Angle(trackpad) + AxisHand.transform.localRotation.eulerAngles.y, Vector3.up) * Vector3.forward;//get the angle of the touch and correct it for the rotation of the controller
updateInput();
if (GetComponent<Rigidbody>().velocity.magnitude < speed && trackpad.magnitude >Deadzone){//make sure the touch isn't in the deadzone and we aren't going to fast.
GetComponent<Rigidbody().AddForce(moveDirection * 30);
}
}
public static float Angle(Vector2 p_vector2)
{
if (p_vector2.x < 0)
{
return 360 - (Mathf.Atan2(p_vector2.x, p_vector2.y) * Mathf.Rad2Deg * -1);
}
else
{
return Mathf.Atan2(p_vector2.x, p_vector2.y) * Mathf.Rad2Deg;
}
}
private void updateInput()
{
trackpad = SteamVR_Actions._default.MovementAxis.GetAxis(Hand);
}
}

Drag and drop/enter your values into the component and you should be ready to go! Check out the second part to add jumping and general code improvements.

Liked it? Take a second to support WireWhiz on Patreon!
Become a patron at Patreon!

11 comments

  1. Hello!

    I’ve been looking allover for a simple solution to walking in VR, using the latest Steam VR and its controllers. There doesn’t seem anything updated, besides you. 🙂
    So, first of all – thank you!
    secondly, I’ve tried your code and instructions, and while the code gives no errors, I could not make it to move\walk in VR using the controllers – nothing seems to happen… 🙁
    This is a screenshot of my set-up – could you please look at it and see what am I doing wrong?
    https://imgur.com/a/tEISAO0

    Thank you,

    1. I can’t figure out anything wrong with it from the picture, if it isn’t throwing any errors I would say to check your steamVR input actions. For me, that’s usually the problem. Heres a video I really like on the subject: https://youtu.be/bn8eMxBcI70

  2. Thank you for your reply!

    Like you suggested – I only added a new input called MovementAxis, uder default, as a Vector2.
    That made the code work and had something to reference to.
    But the controllers don’t react…
    I didn’t even open the controller’s UI Bindings – but maybe I should have? Did you do that?
    Thx and sorry for the trouble,

    1. Ok, I know what the problem is. So when you let steamVR set up default/example bindings it automatically binds them to the appropriate controls. But whenever you create your own actions you need to go in and assign them to the correct controls. Think of it like a variable you can define it and call it whatever you want but unless you update it nothing happens to it.

  3. I tried referencing in this line of the code:
    trackpad = SteamVR_Actions._default.MovementAxis.GetAxis(Hand);

    to “Move” instead of “MovementAxis”:
    trackpad = SteamVR_Actions._default.Move.GetAxis(Hand);

    because “Move” comes with the default example bindings, is also vector2, and should update automatically?

    But it didn’t work… :\

    1. Just changing the name doesn’t make it a default binding, what you need to do is go into the binding UI (button to open can be found at the bottom of the SteamVR input window) click edit on the default bindings for the controller you want to set it for (make sure you have the controllers selected, not the headset), scroll down until you find the trackpad section. Press the plus button next to it and select trackpad in the pop-up. Next click the word none next to the position value of the use as trackpad section you just created. you should see a pop-up with all the vector2 inputs. Select Move (since that’s the input you want to be updated by the trackpad) Then finally click replace default bindings at the bottom of the page and save. Your trackpad should now update the value of SteamVR input. If this doesn’t work for you I could just write a full tutorial on steamVR input.

  4. You’re the king! thank you!! It worked! :))
    2 questions:

    1. what exactly is a “deadzone”? I see that if I set it to 1, I can’t move anymore, and if I set it to -1, it moves on its own. But I fail to feel the difference between 0.0-0.9. 🙂
    I was hoping to control the sensitivity of the touchpad and its affect on the moving.

    2. Can you now help a bit with performing jump via the trigger?

    Thank youuuu,

  5. Also, I’ve tried implementing your code & workflow on the “Player” prefab that comes with the steamvr, which already has a lot of features pre-made, like interacting with objects\teleporting\etc (but no walking!) – but it obviously didn’t work…

    I mean this “Player” prefab:
    https://www.youtube.com/watch?v=iJ0oNYIUFJo&t=1s

    Do you have any ideas how I may combine your workflow with the “Player” prefab?
    Or how I may add “jump” and “grabbing” to your workflow using the trigger?

    Sorry for all of these questions, Steam is super confusing… in Oculus I could do all of this out of the box with the unity plugin, here… it’s… harder… 🙂

    Thank you again,

    1. I just wrote a SteamVR input tutorial that should help, I have a tutorial planned for grabbing but not for jumping. There is some code for making a character controller jump in the Unity docs but I don’t know much about that particular prefab.

  6. Thank you very much!
    You’re the only one doing it properly on the world wide web. 🙂

    I wanted to understand something more fundamental, if that’s ok?
    Let’s say I have a “shooting” script, that works via the regualr:
    if (Input.GetMouseButtonDown)
    How do I map the trigger button on the htc vive controller so it will accept it?

    I think this is the logic that is missing for most people – how to turn your regular input script into steamvr input scripts?

    From there I think I’d be able to understand everything else on my own… 🙂

    Thank you so much!

  7. Hey!

    I wanted to say thank you again, but in the end I decided to stick with the Oculus plugin for unity, since it has OpenVR and just works on the HTC Vive as well.
    It’s player prefab has tons of built in features, and its coding logic is simple for a newbie like me, with its own GetDown system…

    for example, for triggering a “shooting” animation on a gun:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;

    public class ShootingVR : MonoBehaviour {

    public OVRInput.Button ShootingButton;

    // Use this for initialization
    void Start () {

    }

    // Update is called once per frame
    void Update () {

    if (OVRInput.GetDown(ShootingButton))
    {
    GetComponent().SetTrigger(“Fire”);
    }
    }
    }

    Thank you though for everything!!!

Comments are closed.