I am using Unity and Riptide. Riptide is used to send packets between client/server.
What I want to achieve is a smooth transition between the different position states of other players. I don't have any server authority. Clients send their positions and the server redirects them to the other connected clients.
The clients send their positions to the server at a consistent frequency, and the server sends positions of clients to all clients at another, slightly lower, frequency. At the moment it's only really smooth when I use low send frequency for the server, such as 0.5 seconds. When testing with higher frequency, e.g. 0.1s, there is some amount of lag/jitter/bounciness. It makes the player seem to not have constant acceleration, and so makes it not look as it should.
I have read about entity interpolation here, and also here. And below is an implementation for interpolating all the players client side.
// called when a new position packet arrives from the server
void UpdatePlayerPositionBuffer(int id, Vector2 newPosition) {
Player player = null;
ClientManager.Instance.OtherPlayers.TryGetValue(id, out player);
if (player != null) {
player.PositionBuffer.Add((Time.time, newPosition));
}
}
// called every frame by unity. Time.time is the total elapsed time
void Update() {
// interpolationDelay is set to double server send rate as recommended by valve
float renderingTime = Time.time - interpolationDelay;
foreach (Player p in ClientManager.Instance.OtherPlayers.Values) {
while (p.PositionBuffer.Count >= 2 && p.PositionBuffer[1].time < renderingTime) {
p.PositionBuffer.RemoveAt(0);
}
if (p.PositionBuffer.Count >= 2) {
float t0 = p.PositionBuffer[0].time;
float t1 = p.PositionBuffer[1].time;
bool inbetween = t0 <= renderingTime && t1 >= renderingTime;
if (!inbetween) {
continue;
}
Vector2 p0 = p.PositionBuffer[0].position;
Vector2 p1 = p.PositionBuffer[1].position;
p.Position = Vector2.Lerp(p0, p1, (renderingTime - t0) / (t1 - t0));
// set the position of the object in the world
GetPlayerObject(p.Id).transform.position = p.Position;
}
}
}
public class Player {
public int Id;
public Vector2 Position;
public List<(float time, Vector2 position)> PositionBuffer = new();
public Player(int id, Vector2 position) {
Id = id;
Position = position;
}
}
It is not getting stuck in the “in-between” case, and I always have positions available for interpolation.
Here is a video showcasing the problem: video
The red squares are the players. The one with the white dot is the local player for that instance. As you might be able to see - the local player is moving smoothly while the other is lagging.
If you by any chance think you know what the problem may be please tell.
Original post here: https://stackoverflow.com/questions/77072785/entity-interpolation-not-being-smooth-at-higher-server-send-frequency