Teleport Part 1
Prequisites
- Completed Getting Started with VR for Godot and have a working world.
- Completed VR Controller Input for Godot
Setup
Let's make sure we are on the same page with our player. I like to use a general Node3D as my root node and place my VR rig inside it, this way I can add other nodes as components and nothing will be dependent on VR. If your player root is an XROrigin, you can open the scene, right-click and choose Change Type... and rearrange your nodes as needed (or rebuild your player entirely is you wish).
Here is my layout:
You also must have completed the page for VR Controller Input. For this guide, we will focus on the right hand. You may have more code, but here is the bare-bones for my Right Hand:
using Godot;
using System;
public partial class RightHand : XRHand
{
public override void OnTriggerPressed()
{
GD.Print("Right Trigger pressed...");
}
public override void OnTriggerReleased()
{
GD.Print("Right Trigger released...");
}
}
Please TEST IN VR and make sure we are on the same page before proceeding!
Raycasting
Our goal will be to teleport our entire object by pressing a button on our right controller (trigger in this case), aim an area in our level, and if that area is found to be a teleport area, releasing that button will move our player to that position.
First, create a new script in your FileSystem window, the language will be C#, inherits from Node3D, leave Template unchecked, and set the path in an appropriate place, named TeleportArea.cs. This class can be left empty for now, it will be useful later as any object in the level that holds this script will make the area a valid teleport area.
Select your RightHand (XRController3D) and add a new child node called Raycast3D. You may rename it if you wish, but for now edit the following properties:
- Target Position: x: 0.0, y: -100.0, z: 0.0 (note the y is in the NEGATIVE. This is the distance your teleport area will emit)
- Transform/Rotation: x: 90.0, y: 0.0, 0.0 (this will rotate the Raycast3D to point out from the aim of you controller)
Finally, in the Debug menu at the top of the editor, go to Debug and check Visible Collision Shapes. This allows you to see active collision shapes and raycasts during play. This is for TESTING purposes only!
If you hit play now, you should be able to see your Raycast3D emitting from your controller. I would suggest here placing a CSGBox3D, check Use Collision, set the Size to something meaningful, like x: 5.0, y: 0.01, z: 5.0, and assign the script TeleportArea.cs to the Script entry.
The inspector has Script set to TeleportArea.cs which was beyond the scrollbar.
Now we can start editing RightHand.cs
Raycasting Code
For our class, we need some properties:
[Export] Raycast3D raycast3D;
[Export] Node3D playerRig;
TeleportArea validTeleportArea;
bool teleportButtonPressed;
Vector3 teleportLocation;
The first two properties will allow us to assign these nodes in the editor's inspector. Raycast3D is the node attached to our hand and what we will use to access the hit data, and the other is the Player Rig. I typically will assign this to the root of my Player scene.
The property validTeleportArea is what will be cached when our raycast detects an object that is the correct type. The other two properties will help us execute the teleport.
Create a new Process method
public override void _Process(double delta) {}
and in here add the following code:
if (!teleportButtonPressed) { return; }
var target = rayCast3D.GetCollider();
if (target is TeleportArea area)
{
validTeleportArea = area;
teleportLocation = rayCast3D.GetCollisionPoint();
}
else
{
validTeleportArea = null;
teleportLocation = Vector3.Zero;
}
- Line 1: let's ignore everything if we are not pressing our teleport button
- Line 3: Create a variable called target that is collecting the collider that the raycast is hitting
- Line 5: If our target is the type TeleportArea and not a regular collision, let's set our valid teleport area to what we are hitting and set the teleport location to the current POINT our raycast is hitting (the point on the collision).
- Line 10: Reset everything if nothing is valid.
Next, let's make our boolean teleportButtonPressed meaningful. Our process method will only run if our button is pressed (which saves performance) so let's design our teleport execution to activate when pressed (and held) and on releasing the button will commit the teleport execution. Add
teleportButtonPressed = true;
to our OnTriggerPressed() method.
For OnTriggerReleased() method, add the following code:
public override void OnTriggerReleased()
{
teleportButtonPressed = false;
if (validTeleportArea != null)
{
playerRig.GlobalPosition = teleportLocation;
}
}
Essentially, if our valid teleport area is, well, valid we will set our player's global position to be the teleport location point we cached earlier. Finally, on line 3, we always set our button pressed back to false to prevent the code above to continue running.
Test!
Save all your code. Return to the editor and click the build button. Be sure to assign Raycast3D and PlayerRig in the editor!!
From here you should be able to teleport around. Our big issue currently is that we are using a Debug layer in our editor to show our raycast and without this debug there is no way to indicate to our player where they are looking to go. We will fix this in Part 2 along with the final code.




