On June 3rd Felix Schade and I sat together to get started on the VR controls for our Game. Although it’s not absolutely necessary for our game per se; we wanted to allow the player to interact with most of the items in their environment, because that’s what players will attempt to do when they first enter a VR game. I had thought of different approaches beforehand, but eventually we decided on the simple childing method for loose items. For hinged objects (like doors or levers) we didn’t do any controls, because we don’t plan on having anything of that sort in the game.
The Controls-system went through a long iteration process. We used the standard Unity SteamVR Plugin from the Assetstore and followed this tutorial for starters. However since the endresult from those tutorials still have a few shortcomings, we still had lots of work to do.
This is the resulting GameObject Hierarchy for our CameraRig. As you can see there are two Controllers (left&right) childed to the CameraRig GameObject. The way we wrote the code is that each of the controllers works independently from the other, so you could theoretically play with just one controller.
Each of the Controllers has these Scripts on it: WandController, InputManager, InteractWithWorld and Teleporter (not implemented yet). They also have a child GameObject which has a Spherecollider (trigger) and the GrabSphereCollDetection Script on it. There is also a ModeManager Script attached to the Camera(eye) GameObject which deals with changing between the noir and the real-world look. All Grabbable items must have the InteractableObj Script, and the “Interactable” tag on them, as well as a rigidbody and a collider.
So how do you grab something?
The position of the controllers are tracked by the Plugin, we didn’t have to write that ourselves. So; you move the controllers to the item in virtual space. The Spheretrigger enters the collider of the interactable object, and the object is saved for this sphere (controller).
Now you press the GripButton. The GripButton is the button labled as 8 in this image. There is a GripButton on both sides of the controller, but they behave as one Button.
The WandController Script checks for that Input (and others) in the Update function, and then makes it available to other Scripts as public bool variables.
Now the InteractWithWorld Script takes action. This script is the main script dealing with grabbing objects.
In the Update function it checks for Input on the GripButton. If the GripButton is pressed, and there is an item in the grabsphere, and the controller is not already holding an object, the object will be grabbed. Also, if the object is already held by the other controller, the other controller will lose connection with the object (DeleteFromHand). The following steps are necessary to grab the object: the rigidbody is set to a velocity of zero and it stops using gravity. Additionally the object is parented to the grabSphere, which is parented to the controller, so now the object directly follows the position and rotation of the controller.
When the Object is dropped, it’s parent will be reset to its initial value (just null at the moment), gravity will be enabled again, and all references of the object will be removed from the wand controller (DeleteStuffFromHand). However before the references are deleted, the object will take on the velocity/angular velocity of the wandcontroller, so you can actually throw objects. After trying several of our own approaches on throwing, and none of them working as intended, we eventually found this method from thestonefox and used that. Now you can pick up an Object, move it around, and throw it away. We also made it so that objects cannot go through other objects, so when you move your hands through a virtual wall, the object will get stuck on it, and eventually fall from your hands. Furthermore we made it so that when you switch between real-world and noir mode, you drop those objects in your hands that do not exist in the other mode.
Check out the Tech-Demo Video we made here: