• Register
Post tutorial Report RSS How to open a VR door in Unity and SteamVR

Opening doors is a common task in games. In this article I will show you how you can implement a door mechanic in Unity for VR.

Posted by on - Intermediate Client Side Coding

In my VR business simulation Shopkeeper Simulator VR, hand interaction is generally achieved through the SteamVR Interaction System. Let's take a look at the 3D scene in Unity to visualize what we are going to talk about:

Fridge door in closed statae


Fridge door in closed state

Fridge door in opened state


Fridge door in opened state

Object hierarchy

To move the fridge door independently from the fridge body, the door was modeled as a separate mesh in Blender:

Fridge object hierarchy in Blender


Object hierarchy in Blender

After we exported the file as FBX, the imported hierarchy on the Unity side looked like this:

GameObject in Unity


Object hierarchy in Unity (irrelevant children obfuscated)

Handle explained

The "Handle" GameObject is the one which should react to the player's hand. Therefore, it was also separated from the door itself. The handle needs two components: The Interactable component which is part of the interaction system, a collider and the script OpenDoor which is explained further below.

Handle GameObject in the inspector


"Handle" GameObject in the inspector

Script OpenDoor.cs

using UnityEngine;
using Valve.VR.InteractionSystem;
 
 /*
  * This class is attached to a door handle. The door handle is child of a door.
  */
 public class OpenDoor : MonoBehaviour
 {
     private Vector3 force;
     private Vector3 cross;
     private bool holdingHandle;
     private float angle;
     private const float forceMultiplier = 150f;
 
     private void HandHoverUpdate(Hand hand)
     {
         if (hand.GetStandardInteractionButton())
         {
             holdingHandle = true;
 
             // Direction vector from the door's pivot point to the hand's current position
             Vector3 doorPivotToHand = hand.transform.position - transform.parent.position;
 
             // Ignore the y axis of the direction vector
             doorPivotToHand.y = 0;  
 
             // Direction vector from door handle to hand's current position
             force = hand.transform.position - transform.position;
 
             // Cross product between force and direction. 
             cross = Vector3.Cross(doorPivotToHand, force);
             angle = Vector3.Angle(doorPivotToHand, force);
         }
         else if (hand.GetStandardInteractionButtonUp())
         {
             holdingHandle = false;
         }
     }

     void Update()
     {
         if (holdingHandle)
         {
             // Apply cross product and calculated angle to
             GetComponentInParent<Rigidbody>().angularVelocity = cross * angle * forceMultiplier;
         }
     }
 
     private void OnHandHoverEnd()
     {
         // Set angular velocity to zero if the hand stops hovering
         GetComponentInParent<Rigidbody>().angularVelocity = Vector3.zero;
     }
 }

The two methods HandHoverUpdate and OnHandHoverEnd are specific to the SteamVR interaction system. They are called by the interaction system every frame the hand hovers over an interactable object and when the hovering ends respectively.

Basically, we are using the cross product of the force vector (pulling force of the hand) and the vector that points from the door's hinge to the transform where the hand is holding the handle (called "doorPivotToHand" vector). Together with the angle between the force vector and the "doorPivotToHand" vector, the angularVelocity is calculated and applied in FixedUpdate(). Note that FixedUpdate should be used and not Update, since we are changing a RigidBody's angular velocity.

Notice that in order to work, the door must have a Rigidbody, a collider and a Hinge Joint component to limit the door's angle. The HingeJoint's limits were set to 0 min and 90 max:

GameObject


The GameObject "FridgeBody" needs a rigidbody with enabled isKinematic property and gravity equal false because we don't want the body to be controlled by the physics system and influenced by gravity. It is mandatory for the HingeJoint to work though.

I hope you found this little insight into our game Shopkeeper Simulator VR helpful for your own projects. If you found this useful, please leave a comment below and/or share the article! Also post any questions you might have.

Post comment Comments
inferBee
inferBee

Thanks for posting this article about Unity, as I am a Unity Fan :)

Reply Good karma Bad karma+1 vote
Guest
Guest

This comment is currently awaiting admin approval, join now to view.

Guest
Guest

This comment is currently awaiting admin approval, join now to view.

Post a comment

Your comment will be anonymous unless you join the community. Or sign in with your social account: