This code and an example scene are included in the VR instincts plugin on github.

I did not expect it but my previous walking tutorial has become one of the most popular articles I’ve ever written. For me it’s strange because Its a very short undetailed tutorial. As we all know, us programmers love improving our code, and I have improved my code quite a bit. So the logical decision was to make another article that is a lot better than the last one, with that, let’s get started. I’m going to refer to my previous code quite a bit so if you want to read my previous article, you can do so here. The code still works and is great if you just want to walk around, so take a look.

This is what the final code looks like

Ok, so the changes I’ve made from the last article are pretty significant. First, I added the ability to jump. It was easy enough but brought to light a problem with the code, If you notice in the above video when I jump while moving towards the main pillar cube and bump into it, I fall down. Simple right? False. In the original code (with jump added) I would stick to walls when moving towards them, this also stopped me from sliding along walls I was pressing against. I also changed the code from the movement itself so that it always applies the perfect amount of force to move in the direction you want, instead of using an if clause. That’s about it except for a few other changes like changing the class name to Player instead of Movement. So let’s get to the code:

using UnityEngine; using Valve.VR; public class Player : MonoBehaviour { private Vector2 trackpad; private Vector3 moveDirection; private int GroundCount; private CapsuleCollider CapCollider; public SteamVR_Input_Sources MovementHand;//Set Hand To Get Input From public SteamVR_Action_Vector2 TrackpadAction; public SteamVR_Action_Boolean JumpAction; public float jumpHeight; public float MovementSpeed; public float Deadzone;//the Deadzone of the trackpad. used to prevent unwanted walking. public GameObject Head; public GameObject AxisHand;//Hand Controller GameObject public PhysicMaterial NoFrictionMaterial; public PhysicMaterial FrictionMaterial; private void Start() { CapCollider = GetComponent<CapsuleCollider>(); } void Update() { updateInput(); updateCollider(); 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 Rigidbody RBody = GetComponent<Rigidbody>(); Vector3 velocity = new Vector3(0,0,0); if (trackpad.magnitude > Deadzone) {//make sure the touch isn't in the deadzone and we aren't going to fast. CapCollider.material = NoFrictionMaterial; velocity = moveDirection; if (JumpAction.GetStateDown(MovementHand) && GroundCount > 0) { float jumpSpeed = Mathf.Sqrt(2 * jumpHeight * 9.81f); RBody.AddForce(0, jumpSpeed, 0, ForceMode.VelocityChange); } RBody.AddForce(velocity.x*MovementSpeed - RBody.velocity.x, 0, velocity.z*MovementSpeed - RBody.velocity.z, ForceMode.VelocityChange); Debug.Log("Velocity" + velocity); Debug.Log("Movement Direction:" + moveDirection); } else if(GroundCount > 0) { CapCollider.material = FrictionMaterial; } } 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 updateCollider() { CapCollider.height = Head.transform.localPosition.y; CapCollider.center = new Vector3(Head.transform.localPosition.x, Head.transform.localPosition.y / 2, Head.transform.localPosition.z); } private void updateInput() { trackpad = TrackpadAction.GetAxis(MovementHand); } private void OnCollisionEnter(Collision collision) { GroundCount++; } private void OnCollisionExit(Collision collision) { GroundCount--; } }

There’s a lot, I know but we really only need to cover the update function with token explanations for all the extra functions. First, we have all of our private variables:

public SteamVR_Input_Sources MovementHand;//Set Hand To Get Input From public SteamVR_Action_Vector2 TrackpadAction;//action for getting trackpad input public SteamVR_Action_Boolean JumpAction;//get jump action public float jumpHeight;//set height in meters that we can jump public float MovementSpeed;//set speed in m/sec we can walk public float Deadzone;//the Deadzone of the trackpad. used to prevent unwanted walking. public GameObject Head;// used for the position of the head public GameObject AxisHand;//Hand Controller GameObject public PhysicMaterial NoFrictionMaterial;//I'll explain these later public PhysicMaterial FrictionMaterial;

Then we have our update function:

void Update() { updateInput(); //#1 updateCollider(); 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 Rigidbody RBody = GetComponent<Rigidbody>(); if (trackpad.magnitude > Deadzone) //#2 {//make sure the stick isn't in the deadzone CapCollider.material = NoFrictionMaterial; if (JumpAction.GetStateDown(MovementHand) && GroundCount > 0) //#3 { float jumpSpeed = Mathf.Sqrt(2 * jumpHeight * 9.81f); RBody.AddForce(0, jumpSpeed, 0, ForceMode.VelocityChange); } RBody.AddForce(moveDirection.x*MovementSpeed - RBody.velocity.x, 0, moveDirection.z*MovementSpeed - RBody.velocity.z, ForceMode.VelocityChange); //#4 } else if(GroundCount > 0) //#5 { CapCollider.material = FrictionMaterial; } }

#1) We first update the position of our collider and the input from the trackpad which we then use to find an angle that we then offset by the rotation of the controller and multiply by a Vector3 to get our direction of movement as a vector, we also set up a few variables.

#2) see we are touching somewhere outside the dead zone and then set our colliders material to a physics material with no friction.

#3) we check if we want to jump and if we do, calculate the perfect amount of force to jump to the specified height and apply it.

#4) Apply movement force

#5) If we aren’t moving set colliders material to on set with high friction.

That’s about it for the code but I want to explain physics materials a bit better, to create them just go to the unity file browser and right-click and create a Physics material. Now when you click on it you should see something like this:

Simply put Dynamic friction is how much force you need to keep things moving and Static is how much you need to start things moving. What we need to do is to make two materials. One with lots of friction, one with none. You can see the lots of friction one above, to make the other just set all the floats to 0 and the Combine settings to Minimum. From there set up you scene components as described in the last tutorial, fill all the variables on the script and you are walking!