Hello!
I am a fairly active guy over here at the Networking section. I try to help out. And more often that I would like, I see a common mistake.
Most people setup their multiplayer games as follows:
Movement get’s calculated on client.
Client sends the input to server
(Optional) Server verifies if the distance is realistic and maybe even does physics checks.
Server sends position to other clients
Clients store the position they got from server as a Vector3,
and each Update. They lerp towards that position. Usually with some int multiplied with Time.deltatime for the t parameter.
The problem with this is:
To explain this and make it easy to understand. Lets remove the Time.deltaTime and pretend that the Update runs 30 times a second.
If our int called LerpSpeed is then something like 0.25.
Everytime update is called. We get 25% closer. In theory, this means we never actually reach the target. We just get 25% closer every time. And the first few iterations of the Update is going to move the player more than the later ones. You can start to see the problem?
(I even found a open PR on the HLAPI where this was present)
https://bitbucket.org/Unity-Technologies/networking/pull-requests/8/networktransform-interpolation-when-used/diff
Solution:
The solutions are fairly simple.
One option is to always have two values stored. The target, and the position when the lerp started. Then lerp from the position where we started, to the target position.
Option number two is to use a very handy method.
Transform.MoveTowards. It will move towards the target with the same speed all the time.
Using that you can use MoveTowards from current position to targetPosition. And your t can be a LerpSpeed * Time.deltaTime.
And if you send position at a fixed interval. You can even do more clever things:
You can basically calculate the distance between currentPosition and targetPosition when you get it. And then you can calculate the LerpSpeed (You would do this each time you get a update from Server) so that the MoveTowars will have reached it’s destination aproximatly when the next update arrives.
There is also a rotation equivilant for this. Quaterion.RotateTowards, works the same way.
And for the more advanced people who would like to combine Interpolation and Extrapolation. You could calculate the direction vector from currentPos and targetPos, and use MoveTowards but the targetPos is the direction (Basically extended). Ofcourse to do this you would also have to notify the clients when somebody stops, otherwise people would just fly all over the place. But that’s for you guys to look into ![]()
Hope you found this helpful,
Thanks - TwoTen