What is the best way to smooth player movement for network hiccups? Interp? Ease? (no physics)
So my online multiplayer game has simple 6DOF movement using the floating pawn movement class. When you move in any direction, the speed is 3500 - no acceleration, no physics force. You just go 3500 immediately. I set up my simple server movement replication like so and it works perfectly with a good connection:
But of course, on worse CPUs/network connections it can look jittery. For my case, what is the best way to "smooth" the jitter so that when the affected character's movement replicates to other clients it doesn't jitter or teleport but rather moves smoothly in the predicted vector? I imagine it's one of the VInterp or Ease functions, but I am at a loss where to get a sort of "previous actor location" so that the two vectors I am easing from and to are legit. In other words, Interp and Ease require two vectors to smooth. I can get the current actor location, but what is the other vector I am trying to get? Is there another way to accomplish the fakery I'm trying to achieve?
For good measure, here are three ways that aren't working really, but are doing something. The Ease function seems to smooth the best but I am basically using the same location from a few ticks before to simulate a "previous" actor location.
To sum up what I am trying to achieve: I don't want my players to see enemies teleport/jitter when there are network or client updating hiccups. I'd rather see a smooth "catching up" to where the enemy now is. (I think some call this rubber banding?)
Well there are a few approaches, but I'm going to suggest one that I think will be pretty straightforward and fairly robust in most situations.
First of all, I'm assuming you're talking about smoothing the location of other players you see when playing, not your own player. Those are two different problems really (and the first is the easier to solve).
First of all, you'll want to be able to detect whether the client has been moved by a network update. In blueprints this is a little messy with Blueprint-only projects right now as we do not have a callback to tell you the network update happened. The most reliable way to do this is probably have your own replicated location, rotation, and possibly velocity set by the server each update, and catch the RepNotify event for that struct on the client (In blueprints select "RepNotify" under "Replication" for your variable). When the client detects that the network location from the server arrives, this is your "new" server location. You can then choose how to use this new location.
One approach (the simplest) would be to turn off the "Replicate Movement" flag on the actor, and do the interpolation yourself to the server location on the client. Turning off this flag means the server won't do the normal replicate and change of location for the client that happens automatically. Then you could do an interpolation in the tick for the client from current position to the server replicated position, however you like (EaseIn, Lerp, etc). (By the way, make sure you are factoring in the Alpha or DeltaTime parameters to your Ease or Lerp functions!)
Alternatively, you can leave replicated movement on (meaning the root component will teleport to the server location when it's updated), but interpolate another part of your pawn to that location instead. For instance, say you have a sphere collision root, and an attached mesh. You could let the server teleport the sphere, and update the relative location of the mesh to "undo" the server change, essentially leaving it in the spot in the world. In code this looks like this (I've simplified it to make it more readable I hope, even if you aren't a programmer):
Then each tick you decay the relative offset of the mesh towards zero, meaning you try to move it back to the root position. This is similar to how the engine code does this for Characters (UCharacterMovementComponent::SmoothCorrection figures out MeshTranslationOffset based on the change in location, and SmoothClientPosition_Interpolate decays it toward zero with some simple code (again simplified):
The advantage here is that your are moving the invisible gameplay-relevant collision to exactly match the server collision as soon as possible, but slowly moving the visual representation (the mesh) over time to reduce choppiness.
Both approaches mentioned above should be compatible with continuing to update locations based on a velocity during Tick, which will further maintain the smooth look on clients.
Hope this helps!
(Note: in code, detecting the network change in location is much easier, you override PostNetReceiveLocationAndRotation() and you can record the change in location, knowing this came from a network update).
answered Sep 12 '16 at 10:45 PM
Follow this question
Once you sign in you will be able to subscribe for any updates here