Wall Walking Example
This guide will go over how to use the Repositioning Remote Players technique to create what appears to be an anti-gravity effect. Just know that this system is an illusion. The local player is never actually rotated, but simply teleported to a duplicate of the world that is itself rotated.
- Overview
- Preparing the World
- Moving Between Orientations
- Saving Current Orientation
- Station Object
- Entering the station
- Handling Players Entering And Leaving The Station
- Update Station Position Logic
- Player Object Pool Setup
- Linking Origin to the ObjectPool
- Other Improvements
- Other World Ideas
- Example VRChat Worlds
Overview
This guide will go over how to use the Repositioning Remote Players technique to create what appears to be an anti-gravity effect. Just know that this system is an illusion. The local player is never actually rotated, but simply teleported to a duplicate of the world that is itself rotated.
https://twitter.com/CyanLaser/status/1180655212568043520
Example Project Download
All Examples for this guide can be downloaded from my GitHub. Please continue to follow the rest of the guide if you want to implement this yourself as the technique is very strange and may not make sense looking at the files alone!
Overview
There are 4 items required for this system:
- The world with duplicates for every orientation
- A way to move between each orientation
- A system to designate which orientation you are currently
- The RRP system + Object Pool to distribute one per player
- Position remote players based on your current orientation
The first three items are simple. The last item is where it gets complicated. You can ignore the player pool as that has been solved through prefabs like CyanPlayerObjectPool. It all comes down to how players are positioned in the scene.
The idea is that for the local player's current world orientation, you sync their relative position. Every other player will then calculate where that position is relative to their orientation, and set the player's station there.
Preparing the World
This guide will go over how to make a room where you can walk on the floor and on the wall, but you can extend this to any number of orientations.
The first thing you should do is create a spawn area. This area will not be part of the wall walking room but is still needed:
- This will be a safe area outside of the system
- Some people can get sick just thinking about odd rotations
- A player must initiate to enter the system
- You can use this as a way to catch for errors when people don't enter the station
- Have an area where you can drop portals
- Portals in the system will only be in the orientation dropped
Next, create your room. This can be as complicated as you want. Ensure that everything is under one parent. This parent will be the origin of the world and how we determine relative position between orientations.
When you have the room ready, duplicate it, move it out of the way, and rotate it so that the part you want to walk on is now the new floor. Note that normally you wouldn’t let room orientations see each other.
Moving Between Orientations
With the world ready, we need a way to enter it and change orientations. For simplicity in this guide, we will use an interact button to do all this. Create a new program in your Udon compiler of choice. Interact, Teleport the player to a destination Transform. We will add more later.
Saving Current Orientation
As mentioned in the overview, we need to save local player's current orientation to know how to sync their position as well as apply positions of all other players.
Create a new object, call it Origin, and create a new Udon program for this object. The program should have a public Transform variable that can be set, and an event that when sent, will copy the position and rotation of the transform variable and set itself to that position and rotation.
Now we need to update our original buttons to set the transform variable and send the event to this origin object. After teleporting the player, add logic to set the transform variable to the transform of the orientation we are going to. Once set, send the event.
It is a good idea to set the origin’s transform to the same position and rotation as the first room orientation. This way, by default, all players will appear in the first room, instead of any other arbitrary location.
Station Object
At this point, we can start working with stations to start repositioning players. For now, we are only going to create one station to test the system before extending it to all players.
Create a new object. Add a VRCStation component to it.
- Set Mobility to Immobilize
- Set Seated to unchecked
- Set Disable Station Exit to checked
- Set Can Use Station From Station to unchecked
Create another object and set it as a child of the station. This will be for the player's position. In the station script, set the "Player Enter Location" and "Player Exit Location" to this new child transform. Create another object as a child of the station and add VRCObjectSync. This will be how the player's relative position is synced to all players.
Entering the station
Now we need to create a program to perform the logic for the station. This will consist of multiple events to handle different sections. Create a new program and attach it to the station object.
Create a new custom event and call it "_EnterStation". This event will be used to enter the station. There are three items that need to happen here:
- Set the station mobility to Mobile
- Take ownership over the object sync object
- Have the local player enter the station.
Outside of the station object and in the Origin object's program, add a SendCustomEvent to enter the station. This will automatically update all buttons to properly enter the station, and enter the system.
Handling Players Entering And Leaving The Station
Since anyone can enter the station, we need to save the player currently in it to know what logic to perform later.
Create a new VRCPlayerApi variable to store the player in the station. Add the OnStationEntered event, and save the entered player in the variable. Also add the OnStationExited event. Instead of saving the player, set the player variable to null. Also in the station exited event, set the station mobility to Immobilize. This just cleans up in case one player uses it, stops, and another player wants to use it.
Update Station Position Logic
Now that we know when someone is in the station, and if that player is local vs remote, we can update the station objects appropriately.
- Add a public Transform variable. This will be set with the origin we created earlier.
- Add the Update event. The first thing we need to check is if the sitting player is valid. If they are invalid, we can stop early as no one is using the station.
- Next, check if the player is the local player. In both the local and remote case, we will need to perform some math. Create a custom event for updating position for local and remote.
First, updating positions for the local player. Get the local player's position and rotation, and set the station's location to these values. Having the station follow the local player removes issues with teleporting on exiting the station.
Next, get the origin transform's "worldToLocalMatrix". This 4x4 matrix will convert world space coordinates into the local space coordinates relative to this origin object. Use matrix.MultiplyPoint on the player's position to get the local position. Use matrix.get Rotation and multiply this with the player's rotation to get the local rotation. Now set the ObjectSync object to this position and rotation.
Now to handle updates for the remote player. We basically need to do the opposite here.
First get the position and rotation of the objectSync object. Also get the origin transform's "localToWorldMatrix". Note this is local to world and not world to local like the previous one. Use matrix.MultiplyPoint on the sync's position to get the new world position. Use matrix.get Rotation and multiply this with the sync's rotation to get the new world rotation. Finally, set the station's location to this position and rotation.
With those events created, we need to go back and add two send custom events in previous areas. Since players will teleport when entering and leaving stations, we can reduce movement by updating the station position just before entering and just after exiting. In the "_EnterStation" event, just before entering the station, add SendCustomEvent to the local update position event. In the OnStationExit, check if the player was local, and also add the SendCustomEvent
With this, one player can enter the station, and other players can observe them walking on the wall.










































