VR Climbing Tutorial – Unity SteamVR

It seems like climbing in VR has become a given. If you have a VR headset, you have a climbing app. For a good reason too. Rock climbing is one of those things like skydiving that people want to do, but don’t want to. (I personally want to do the real thing but I’m poor) But that’s enough of that let’s start coding.

The method I came up with was inspired by [loud coughing] Apex Legends and how I imagine their clambering mechanic to work. If you pay attention you’ll notice that things that look more climbable, are more climbable. Most VR games that include a climbing mechanic make use of a system where certain objects are grabbable and others are not. (Or they just make everything climbable). My system uses tagged colliders so you can specify what parts of your models you can grab. For example, take this object:

It works is by checking if our hand is inside a grabbable object and we are grabbing and if it is, we move a kinematic empty with a configurable joint to the position of our hand and connect it to our camera rig and offset it by Our ActiveHand’s local position. If that’s too much complication for you, copy and paste. Just a note this builds upon my walking tutorial, if you don’t want to read that just attach a rigidbody and collider to your camera rig.

First we create a script to attach to our hands to keep track of them. Let’s call it ClimberHand:

using UnityEngine;
using Valve.VR;
public class ClimberHand : MonoBehaviour
{
    public SteamVR_Input_Sources Hand;
    public int TouchedCount;
    public bool grabbing;
    
    void OnTriggerEnter(Collider other)
    {
        if (other.CompareTag("Climbable"))
        {
            TouchedCount++;
        }
    }
    void OnTriggerExit(Collider other)
    {
        if (other.CompareTag("Climbable"))
        {
            TouchedCount--;
        }
    }
}

All this does is tell our main script whether or not our hand is overlapping a climbable object plus giving us a way to access the hand gameObject. Now attach your script to both Hands and set the SteamVR input source to the correct hand. Now let’s create our main Climber script:

using UnityEngine;
using Valve.VR;

[RequireComponent(typeof(Rigidbody))]
public class Climber : MonoBehaviour
{
    public ClimberHand RightHand;
    public ClimberHand LeftHand;
    public SteamVR_Action_Boolean ToggleGripButton;
    public SteamVR_Action_Pose position;
    public ConfigurableJoint ClimberHandle;

    private bool Climbing;
    private ClimberHand ActiveHand;

    void Update()
    {
        updateHand(RightHand);
        updateHand(LeftHand);
        if (Climbing)
        {
            ClimberHandle.targetPosition =  -ActiveHand.transform.localPosition;//update collider for hand movment
        }
    }

    void updateHand(ClimberHand Hand)
    {
        if (Climbing && Hand == ActiveHand)//if is the hand used for climbing check if we are letting go.
        {
            if (ToggleGripButton.GetStateUp(Hand.Hand))
            {
                ClimberHandle.connectedBody = null;
                Climbing = false;

                GetComponent<Rigidbody>().useGravity = true;
            }
        }
        else
        {
            if (ToggleGripButton.GetStateDown (Hand.Hand)||Hand.grabbing)
            {
                Hand.grabbing = true;
                if (Hand.TouchedCount > 0)
                {
                    ActiveHand = Hand;
                    Climbing = true;
                    ClimberHandle.transform.position = Hand.transform.position;
                    GetComponent<Rigidbody>().useGravity = false;
                    ClimberHandle.connectedBody = GetComponent<Rigidbody>();
                    Hand.grabbing = false;
                }
            }
        }
    }
}

Now attach this script to your [CameraRig] and drag in your hands and set your steamVR actions, Now for that last option (ClimberHandle) create an empty and add a configurable joint to it, set your rigidbody to kinematic and set all the configurable joint linear drives to 5000.

After that try it out by creating a default cube and tagging it as Climbable. You should now be able to grab that cube and pull yourself around. If it doesn’t work always check your SteamVR bindings and save them, It’s always the issue. If you want to get the result where I was only able to grab certain parts of a model, you can do that by creating child game objects with colliders that are tagged climbable instead of the parent object.

That’s about it for this one, If you have any questions (check bindings first) just post them in the comments below.

To Do: Resize walking collider so you can stand on top of an object you have just climbed without glitching your hand through the floor.

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