Reposting this question from Discord. User @Thundernerd asked:
My question is: Is there a way to sync the position and treat it as a local position? Let’s say I have three players and they all have their own playing field. I want the local player’s playing field to be in the center, and the playing fields of the other two players to be on the left and right side. Is that possible?
An example would be: Tetris. Imagine playing Tetris with two of your friends, every player is playing on their own board. Obviously you want your own to be in the center of the screen and your friends’ boards to the side
Maybe this can help:
For starters, in coherence there is no way to disable the syncing of an object’s position (as of now).
There are however ways to “cheat” to achieve this. One way for instance is to use another network entity with a complex hierarchy (1 child is ok) to act as an intermediate, non-synced parent, to enable the per-Client shifting.
Like in this video:
The Player characters are initially on the root. Their position is synced (obviously) and they have a
CoherenceNode component in order to be parented in a complex hierarchy.
An object called Container is spawned, with a child called Offset. We don’t sync Offset’s position.
If the Player is parented to its own object (so, both authority side), on the non-authority side the Client can shift the intermediate child, effectively seeing the remote player in a different position.
This is a sort of a hack, but it should work reliably if the game doesn’t use limited range LiveQueries… which would lead to entities disappearing for seemingly no reason.
Another simple idea is to render the objects shifted on each Client.
Either by using multiple cameras (in built-in pipeline), or by using URP’s Renderer Features. Also a tutorial.
Using a “Render Objects” pass and its Camera > Position Offset, one can render a series of objects as if they were somewhere else in the world.
This trick can be also effective, although has some downsides:
- It might be costly, as rendering multiple passes is in any case heavier than doing just one. How much, it depends on the game!
- It might introduce visual artifacts (especially the interaction of shadows from different passes)
- It might be unwieldy, as one would need to ensure that all objects to be shifted need to be on a specific Layer, which migth make it incompatible with other layer-ordering.
There is yet one more way, which is not immediately available as of now (see below) but will be in the near future.
One way to shift positions (or any other value, really) is to enable Prediction for that binding in the Config window:
Enabling Prediction means that coherence won’t just apply that value every time it receives an update, but it will send a callback to a registered script, and provide them with the value.
So one could write a simple listener as described on this page and, when the position value arrives, apply it by adding an offset.
public Vector3 offset;
private void Awake()
var positionBinding = GetComponent<CoherenceSync>().Bindings.FirstOrDefault(c => c.Name == "position");
positionBinding.OnNetworkSampleReceived += ApplyWithOffset;
private void ApplyWithOffset(object sampleData, long simulationFrame)
var networkPosition = (Vector3)sampleData;
transform.position = networkPosition + offset;
This is a simple, performant, and very powerful solution, because you can manipulate the data in many creative ways (for instance, scale or stretch the position, rotate it, quantize it, etc.).
Enabling Prediction as of the moment of writing (coherence
1.0.5) only works with objects that have a server-authoritative setup, that is they use the
CoherenceInput component to send inputs to the Simulator and receive state back.
We will enable Prediction and reconciliation as shown above for all bindings in a soon-to-come-out version of coherence.
Thank you for the detailed explanation, very nice to read!
I myself went for option one and it seems to be working as I expected, that is to say, without issues
Another way to achieve the same result is to set
Interpolate On to
Nothing on the playing field prefab. This way, player positions are applied as local positions but the playing fields can still be moved around freely.
Note: This disables all interpolated bindings on the playing field, not just the position, so keep this in mind if you intend to also sync things like scale or rotation.