Ocean Black Studio

Locomotion and Ergonomics

View Lesson here

It’s recommended to support all types of movement. Comfort is important.

Physical Movement

Movement in VR that matches physical movement and provides the most comfortable experience because there is no mismatch of senses that could trigger discomfort.


  • Play areas
    • Small spaces
    • How small is too small for the design?
  • They simply don’t have the mobility, i.e. they are in a wheelchair

Scripted Movement and Avatar Movement

Scripted Movement 

When the perspective moves along a predefined path of motion. This creates vection which is the sensation of movement of the body in space produced purely by visual stimulation.

For example, see yourself riding a rollercoaster while on the couch. Use sparingly

Avatar Movement

A combination of thumbstick, button, headset, motion controllers and gameplay state to drive the motion in a way that makes sense. Studies have shown that the more we move our body while in VR, the more comfortable we can stay.

Immersion is the key to any experience. The more accurately we move to how our character is moving, the better the experience is.

Steering Motion and World Pulling

Steering Motion

The player is controlling inertia.

Near-continuous sex degrees of freedom (6DoF) accelleration and velocity is common and often includes moving at a high speed.

In the past many people didn’t think this would be comfortable.

World Pulling

The player is generally stationary until they grab some point in the world and pull or push it. The world is locked to the controller and movies with it exactly.

Climbing mechanics were the first to use this.


An instant,  or nearly instant, mechanic where you quickly appear somewhere else. This typically works by aiming a beam and pressing a button.

A good example is Projectile Warping, where you warp to wherever you throw or shoot.

Another approach is Projected Avatars. This is when you push the thumbstick and your avatar walks away from you in a 3rd-person perspective. After you are done moving the avatar, the camera shifts to the avatar’s new location.

Implementing Teleports

  1. Go to Packages/VRTK Prefabs/Pointers and drag the ObjectPointer.Curved into the scene
  2. Give it a good name, in this case TeleportCurved.L and TeleportCurved.R
  3. For the Left control curve we set the Follow Source under Pointer Facade (Script) > Pointer Settings to the LeftControllerAlias, then we do the same with the right
  4. To keep the scene organized we create an Object to hold other Objects. In this case We create InputHandlers and reset to origin
  5. Within InputHandlers we create ThumbstickTouched.L and ThumbstickTouched.R
  6. Select both ThumbstickTouched.L and ThumbstickTouched.R
  7. Ensure they have the script OVR Input Touch Action attached and under Touch select Primary Thumbstick
  8. Set Controller to R Touch for right, and L Touch for left
  9. Now we drag the associated thumbsticks onto the Activation Action in the control curves. ThumbstickTouched.L goes to TeleportCurved.L > Pointer Facade > Activation Action and we repeat for the right
  10. Test in VR and we should see some targeting beams coming from the controllers when we touch the thumbsticks


Add The Teleportation Action

  1. Drag Teleporter.Instant from VRTK/Prefabs/Locomotion/Teleporters into the scene
  2. The target of the teleporter is what’s actually moved. Drag PlayAreaAlias into Teleporter.Instant > Teleporter Facade > Teleporter Settings > Target
  3. The offset field needs to be assigned to the headset alias. Drag HeadsetAlias to Teleporter.Instant > Teleporter Facade > Teleporter Settings > Offset
  4. Next drag SceneCameras to Teleporter.Instant > Teleporter Facade > Teleporter Settings > Camera Validity
  5. Under InputHandlers create 2 actions: ThumbstickPressed.L and ThumbstickPressed.R
  6. Add the button action for both and configure them for each controller. Add the OVR Input Touch Action to both
  7. While both ThumbstickPressed.L and ThumbstickPressed.R are selected set OVR Input Touch Action > Button to Primary Thumbstick
  8. Select ThumbstickPressed.L and set OVR Input Touch Action > Button to L Touch and do the same for the right
  9. Now we tell the curves to select the boolean action when these teleports are triggered. Drag ThumbstickPressed.L to TeleportCurved.L > Pointer Facade > Selection action and do the same for the right
  10. We need to add a reference to the teleporter object’s teleport function to this list. Drag Teleporter.Instant to the missing object in both TeleportCurved > Pointer Facade > Selected
  11. Test in VR

Adding a Direction Indicator

  1. Search “Arrow” in the asset finder and find the arrow model
  2. Drag and drop in TeleportCurved.L > ObjectPointer.Internal > Elements > Elements.Cylinder
  3. Reorient arrow as desired
  4. Search “PointerDefaultValid” to find the material the beam is using
  5. Drag and drop that as the material for the arrow
  6. Duplicate the arrow and drag and drop to the same place under the other curve
  7. Create a high-level game object which we can name “ThumbstickPosition.L” Then copy and paste for R
  8. Select both and set OVR Input Touch Action > Axis to Primary Thumbstick
  9. Then assign OVR Input Touch Action > Controller for each hand to their respective L Touch and R Touch values
  10. Drag ThumbstickPosition.L and ThumbstickPosition.R into the InputHandlers object
  11. Now we need to set up the action to rotate the arrows. Create a high-level game object which we can name “AccessRotator.L”. Then copy and paste for R
  12. Next, we need to change the default 2D axis to a 1D axis with our controllers. Within ThumbstickPosition.L create 2 objects named “Thumbstick.X.L” and “Thumbstick.Y.L”. Copy and rename appropriately for R Thumbstick Positions
  13. Select the 2 Y axis objects of the new Thumbstick axis objects. We need to track all of the axis values we want, so this is how we will take care of that
  14. Under Vector 2 To Float > Coordinate To Extract select Extract X. Now we need to make sure that when the Vector 2 values are changed the float converters are notified
  15. To do that we select ThumbstickPosition.L under OVR Input Touch Action > Value Changed add the 2 vectors we just created
  16. Then change the property No Function to Vector2ToFloat > Vertor2ToFloatDoTransform. Then do the same for ThumbstickPosition.R.Now we need to add a Float action to each of the converters. Search “FloatAction”
  17. Select all of the Thumbstick Axis Objects and drag the FloatAction script to their properties Inspector
  18. Add to Vector 2 To Float > Transformed script for each Thumbstick Axis Object it’s own object and change the No Function property to FloatAction > Receive. Next we need to set up the axis rotators to respond to the float actions we just built
  19. Create a high-level game object which we can name “AxisRotator.L” and copy for R
  20. In AxisRotator.L > Axis Rotator Facade drag Thumbstick.X.L into Axis Settings > Lateral Axis and Thumbstick.Y.L into Axis Settings > Longitudinal Axis. Then do the same for R
  21. Drag the TeleportCurved.L > ObjectPointer.Internal > Elements > Elements.Cylinder > Valid Container to AxisRotator.L > Axis Rotator Facade > Target Settings > Target and do the same for the right
  22. Drag the Tracked Alias > Aliases > Headset Alias to AxisRotator.L > Axis Rotator Facade > Target Settings > Direction Offset and do the same for right
  23. Set Teleporter.Instant > Teleporter Facade > Offset Usage to Offset Always With Destination Rotation
  24. Now TEST!

Adding Restrictions to Teleporting

  1. Add a Layer Called “Teleportable”
  2. Save that and put Environment > PlayArea > Floor > FloorCollider into this layer by selecting it at the top of the inspector while selected
  3. Create a new game object and name it TeleportationRule
  4. Search “AnyLayer” in the Asset finder
  5. Find the AnyLayerRule
  6. Drag the AnyLayerRule over to the TeleportationRule
  7. Set AnyLayerRule > Layer Mask to Teleportable
  8. Select the 2 TeleportCurved objects and drop the TeleportationRule into Pointer Facade > Target Validity
  9. Test to make sure you can’t teleport anywhere you shouldn’t

How to Use Teleport Targets

  1. Create a game object and name it “TeleportTargets”
  2. Add 2 components. First search for ActionDisplatcher in the asset finder and add it to TeleportTargets
  3. Do the same with TransformDataProxyEmitter
  4. In the TransformDataProxyEmitter > Emitted list click the + button and drag Teleporter.Instant into the object input and in the function input select TeleporterFacade > Teleport
  5. In the asset finder serach “distination” and drag DestinationPoint Variant to the object list under TeleportTargets
  6. Select all DestinationPoint Variant objects and drag TeleportTargets into Destination Location Facade > Location Events > Activated
  7. Set the function to TransformDataProxyEmitter > Recieve
  8. Set the layer to Teleportable and select Yes, change children
  9. Select the TeleportCurved objects and add a list item to Pointer Facade > Pointer Events > Entered and Exited
  10. Drag TeleportTargets to the Pointer Facade > Pointer Events > Entered and Exited object
  11. Set the Pointer Facade > Pointer Events > Entered function to ActionDispatcher.Enter
  12. Set the Pointer Facade > Pointer Events > Exited function to ActionDispatcher.Exit
  13. Test and make sure the cursor snaps to the different nodes and that you can teleport to them

Snap Turns, Custom Inputs, Player Occlusion

  1. Within InputHandlers create 2 objects named “TeleporterActivation.R” and “TeleportSelection.R”
  2. Search “TeleporterSelection” and add the TeleporterSelection script to TeleportSelection.R
  3. On both set Teleport Activation/Teleporter Selection > Controller to R Touch
  4. Under TeleportSelection.R create 2 game objects named “RightTeleport.X” and “RightTeleport.Y”
  5. Select both and in the asset finder search “FloatAction”
  6. Drag the FloatAction.cs script to both
  7. Assign RightTeleport.X/Y to TeleportSelection.R > Teleporter Selection > Extract X/Y
  8. In AxisRotator.R change Axis Rotator Facade > Lateral Axis to RightTeleport.X and Axis Rotator Facade > Longitudinal Axis to RightTeleport.Y
  9. Disable ThubmstickTouched.R, ThumbstickPressed.R, and ThumbmstickPosition.R by selecting them and unchecking them in the inspector
  10. On TeleportCurved.R change Pointer Facade > Activation Action to InputHandlers > TeleporterActivation.R and Pointer Facade > Selection Action to InputHandlers > TeleporterSelection.R
  11. Now test with the right controller only

Snap Turns on the Left Controller

  1. Disable TeleportCurved.L, InputHandlers > ThumbstickTouched.L, ThumbstickPressed.L,  and AxisRotator.L
  2. Search “axestovector3” in the asset finder and drag the AcesToVector3 object to the scene Hierarchy
  3. In AcesToVector3 change Axes To Vector 3 Facade > Axis Usage Type to Directional
  4. Drag InputHandlers > ThumbstickPostion.L>ThumbstickX.L to Axes To Vector 3 Facade > Lateral Axis and InputHandlers > ThumbstickPostion.L>ThumbstickY.L
  5. Set the Axes To Vector 3 Facade > Lateral Speed Multiplier to 45 and the Longitudinal Speed Multiplier to 0
  6. Search “vector3cache” in the asset finder and add Vector3Cache to AxesToVector3
  7. Add a list item to Axes To Vector 3 Facade > Events and drag AxesToVector3 to the object and change the function to Vector3Cache.CachedData

Fade The Screen on Snap

  1. Search “cameracoloroverlay” in the asset finder and add CameraColorOverlay.cs to AxesToVector3
  2. On AxesToVector3 > Vector 3 Cache > Modified drag AxesToVector3 to the target and select CameraColorOverlay.Blink
  3. Drag TrackedAlias > Aliases > SceneCameras to AxesToVector3 > Vector 3 Cache > Camera Validity
  4. Search “teleportfade” in the asset finder and drag TeleportFade shader to AxesToVector3 > Vector 3 Cache > Overlay Material
  5. Set AxesToVector3 > Vector 3 Cache > Remove Duration to 0.5
  6. Create a new object called “SnapRotator”
  7. Search “vector3tovector2” in the asset finder and add Vector3ToVector2.cs to SnapRotator
  8. Then search “vector2tovector3” in the asset finder and add Vector2ToVector3.cs to SnapRotator
  9. On AxesToVector3 > Axes To Vector 3 Facade > Events add a list item and drag the SnapRotator to the target. Set the function to Vector3ToVector2.DoTransform
  10. Add a list item to SnapRotator > Vector 3 To Vector 2 > Transformed. Drag SnapRotator to it’s target and set the function to Vector2ToVector3.DoTransform
  11. Set SnapRotator > Vector 3 To Vector 2 > Coordinate Map to X To Y And Y To X Exclude Z
  12. Search “transformeu” in the asset finder and drag TransformEulerRotationMutator.cs to SnapRotator
  13. Add a list item to SnapRotator > Vector 2 To Vector 3 > Transformed and SnapRotator to it’s target and set the function to TransformEulerRotationMutator.DoIncrementProperty
  14. In SnapRotator > Transform Euler Rotation Mutator > Target drag Aliases > PlayAreaAlias . Check Use Local Values and make sure Mutate On Axis is only set to Y

Disable Snap-to-Floor

  1. Disable Teleporter.Instant > Internal > SnapToFloor

Prevent Wall Clipping

  1. Search “collisionfa” in the asset finder and drag the CollisionFader under TrackedAlias > Aliases > HeadsetAlias
  2. Drag Aliases > SceneCameras into CollisionFader > Camera Color Overlay > Camera Validity
  3. Add 2 new layers to CollisionFader. One called “FadeCamera” and another called “FadeOut”
  4. Set the CollisionFader layer to FadeCamera
  5. Add Environment > PlayArea > Cabinet > cabinet to the FadeOut layer
  6. Go to Project Settings > Physics and uncheck all FadeCamera boxes
  7. In OVRCameraRig > TrackingSpace Select LeftEyeAnchor, CenterEyeAnchor, and RightEyeAnchor and set Camera > Clear Flags to Solid Color and select black