Restrict WebXR Teleportation by a max distance in meters

Currently the WebXR Teleportation does not have a “maxTravelDistance” option to restrict how far a person can jump to. I would like to create a game where all the players are restricted to teleport in maximum of 3 meter increments. Think of a racing game (red light/ green light), a game of tag, or running from zombies. In this game it would not be fair for a person to cast a teleportation arc that is hundreds of meters at once. I want the teleportation to be fairly limited, e.g. to within a 3 meter radius from the person.

I have played with all these settings:

   this.teleportation =
      this.xrHelper.baseExperience.featuresManager.enableFeature(
        BABYLON.WebXRFeatureName.TELEPORTATION,
        "latest" /* or latest */,
        {
          xrInput: this.xrHelper.input,
          floorMeshes: [],
          defaultTargetMeshOptions: {
            teleportationFillColor: "yellow",
            teleportationBorderColor: "green",
            timeToTeleport: 0,
            disableAnimation: true,
            disableLighting: true,
          },
          forceHandedness: "right",
        }
      ) as BABYLON.WebXRMotionControllerTeleportation;
    this.teleportation.rotationEnabled = false;
    this.teleportation.straightRayEnabled = false;
    this.teleportation.parabolicCheckRadius = 0.5;

By setting a smaller number for parabolicCheckRadius, it kind of gets me close for curved arcs but not for low angles when the arc flattens out. The curved ray is constrained and is not super tall. However once you drop the angle of the controller to near parallel with the floor, there is almost no restriction on the teleportation distance. Even though straightRayEnabled is set to false, when the angle is near zero the arc drawn might as well be a straight line that goes as far as the eye can see.

You can test this by making a teleportable floor that is huge, like 100 square meters with no other obstructions. If you’re not holding the controller with at least a little tilt, the teleportation arc sometimes doesn’t even appear because the target it would need to create is so far it exceeds the ground plane.

Unless there is some other way to achieve this that I’ve missed? Thanks.

@RaananW Any thoughts?

That’s an interesting usecase. We do have the arc-radius but not a max distance.

I guess a form of predicate could work here? A function that will run on each ray sent by the teleportation module that can also return false if you want to prevent the teleportation from working.
I can add something similar. This will solve it in a general way that only requires you to just define the function that checks the distance between you and the future landing point and return false if it is more than 3 units.

Can we do it in a way such that the arc is always drawn though? It’s sometimes confusing if the user is using the thumbstick but because the predicate function returns false the teleportation just doesn’t appear. It makes them think the feature doesn’t work. Or is buggy. I’ve experienced this when holding the controller at a low angle, the target is simply too far in the distance that it is off the plane.

In my opinion a better experience is to have the teleportation target widget appear consistently, but cap it to a max distance if the original distance would have been greater than that.

1 Like

Sure, we can use the blocking mechanism for that. You can block the ray, now you would be able to block it programmatically. does this work?

Blocking is not quite the experience I’m going for. I feel like the teleportation feature (with a max distance option) should just not suggest long ranges for me to hop to in the first place. I’m not a fan of blocking because when you’re frantically running from zombies, you just want to escape quickly and reliably. But there is so much distance sensitivity when in the low x angle of the controller, that players would be very frustrated if blocked when there was plenty of open space to go to.

Just a thought here: Could we maybe work backward from the target? So that if the original target was a distance greater than max distance option, cap the target at the max distance along the same direction, and then draw a line/arc from target back to controller?

Here is a prototype https://thexr.space/spaces/Y5QK7 that you can play with shows that the teleportation feature has an uncomfortable “dead zone” where no arc appears at certain thresholds of low angles. (like if you actually try to point it directly 3 meters in-front of your feet, no ray will come out). Because the target wants to be placed super far, and the plane/ground is not infinite, there is no target to draw. But this can be a confusing experience for new users that don’t know they need to tweak their controller angle higher in order to discover where the teleportation widget will appear.

in that case I would disable one of the two - the arc or the direct line (you have full control). But nonetheless I get what you are saying. The arc can be better implemented to support “straight” teleportation as well - i.e. - make everything an arc that eventually points towards the floor.
The thought behind the current implementation was back-compat - the VR experience helper had straight teleportation lines and I wanted to fully support them as well. But since they can be disabled, you should have more control over the results.

I am just trying to find a generalized approach - when picking the next point, run this function that will return this object, that will be used to do this thing. Now, the 3 "this"es need to be defined :slight_smile:

As an experiment I tried switching between straight line and parabolic ray based on the angle:

// on every frame, get x angle of the hand controller...  
const x = grip.rotationQuaternion?.toEulerAngles().asArray()[0] as number;
      if (x > -0.55) {
        this.teleportation.straightRayEnabled = true;
        this.teleportation.parabolicRayEnabled = false;
      } else if (x <= -0.55) {
        this.teleportation.straightRayEnabled = false;
        this.teleportation.parabolicRayEnabled = true;
      }

This got a tiny bit closer, however, this technique still has a “dead-zone” between -0.9 radians and 0.5 radians where the target will shoot off into infinity.