Annoying little interpolation problem

Started by
9 comments, last by hplus0603 17 years, 4 months ago
So, I've got some basic interpolation going on with my little networking game. In order to test it out, I've slowed down the network send frequency to pretty slow (I believe 5 to 10 times per second). I'm noticing a problem, though, with how motions begin and end. Let's say that a user can turn their ship 10 degrees per game state. Let's also say I'm going to get an update at times 50,60,70, and so on. Finally, let's say that the remote user began turning his ship at state 59 and stops turning his ship at state 71. At time 50, I find out that the remote user is facing 0 degrees. At time 60, I find out that the remote user is facing 10 degrees. At time 70, I find out that the remote user is facing 110 degrees. At time 80, I find out that the remote user is facing 120 degrees, So as you can see, the remote user will appear to spend 10 ticks moving very slowly, then 10 ticks moving at full speed, then 10 ticks moving very slowly. I'm trying to think of a way to compensate for this, and my answers are basically: 1.) more frequent updates, make the problem harder to see, and: 2.) average between multiple upcoming updates instead of just the one. Keep at least 2 newer states, and use spline interpolation on it. The second answer introduces yet more artificial lag, so I'm not particularly partial to it, but it certainly would be smoother. Any ideas from the peanut gallery? If I did go with a spline, how many upcoming states would be best? Would 2 be enough?
Advertisement
make the interpolation client side. Also 5 to 10 times per second isn't slow. 1 time a second or every 2 seconds is slow. Just send a rotation velocity and then a value of the current ship angle. Then just have the ship do client side interpolation and move it in the direction the server told it. If your getting packets at around 2 times a second it will look extremely smooth. Also if the client knows the acceleration rates of the ship and such it makes things even nicer.
Well, angular rotation in my game is instant-on, instant-off, but if it weren't, how would I use the actual angular acceleration to smooth the interpolation between the points better? Is there an interesting mathematical trick to smooth things out better if I know the initial or final velocity and/or acceleration?
oh instant... that's hard to plan for, but you can just iterate between a few frames and move it at intervals along the old and new angle. Might want to implement slow rotating ships, not only is it realistic, it also adds strategy.

If you know the angular velocity you can keep rotating the object. So when the server says to the client "player 1 is rotating at a rate of 5 degrees and his angle is currently 20 degrees" the client goes ok and if the angle is off by more than 10 degrees snap the angle to 20 and as the game plays out on the client and rotates the player's ship 5 degrees every tick.

Then when the next packet comes in say 7 ticks later and says the player is now at 45 degrees, you just do step one again. Your client will have the player at 45 degrees and it looks smooth! then you just update with the new velocity and keep going.

If you add inertia to the ships rotation it looks even more smooth. Because sudden changes in direction are harder to detect because the ship has to rotate against the direction it was going. so the rotation along 5 packets might be -10, -5, 0, 5, 10 instead of -10, -10, 0, 10, 10. You can also figure out the inertia client side and simulate it perfectly.

I've sent packets once every 2 seconds and this looked very good. Gave a good idea of where a player was looking at when they rotated. Especially if your planes fly realistically and turn realistically in space. I used these ideas in a top down mmo test I made.
For large ships the above works very well. it also works with heat-seak player controlled missiles. :)
I actually began with that sort of implementation. I've found it leads to an awful snap-back effect. You'd find out that your opponent was at 5 degrees and turning clockwise, and you'd simulate it forwards for a while and find out later that the play stopped turning a tick or two ago, and you'd have to snap back, so you'd get this annoying snapback every single time someone stopped turning. At one point, when I was predicting the remote objects as far forwards as I was predicting the local ones instead of rendering them in the past, the snapback on a fast-turning ship could easily be 180 degrees.

That's why I switched to interpolating between the 2nd-most-recently-known state and the most-recently-known state. That way, I never get snapback unless I'm forced to start extrapolating or if there's a collision, and there's nothing to be done for those situations.

The more I think about it, the more I think the solution is going to have to be to render 2 updates back, and use all 3 points to make a curve. I'll need pretty frequent updates to keep the latency sane. If I send network updates 10 times a second, every update I buffer by adds another 100ms one way to the latency, so buffering by 3 would be an instant +600ms round-trip ping (for movement, at least). And that seems pretty awful. Which is why I asked about other solutions.
That's a pretty common problem. What you want is extrapolation instead of interpolation. You want to 'guess' what will be the object state, until you receive a packet telling you what his state really is. If the guess is wrong (say, you assumed constant or decaying linear and angular velocity), the object will snap once the correction packet is received. If you want to smooth out the transition with curve fitting or whatever, you can but you'll have to live with the fact that the orientation displayed on the client will not be the same as the orientration sent by the server. It's a trade-of between accuracy and smoothness.

So yeah, I know that CS:S and other FPSes works by running 'behind' a couple of ticks away. So when you always interpolate between two received samples, and rarely extrapolate (like when a packet is lost).

It's virtually impossible to extrapolate player commands or AI in general. Second guessing can be bad. However, some objects can have a predictable behaviour, say, platforms, and will need little work to synchronise them on every clients, while minimising the bandwidth usage. For example, a 'point and click' sytem for moving units on a battlefield. No need to send the unit movement, only send ther target position, and time it will reach the target, and it can be simulated relatively accurately on clients.

So in the end, it's all a matter of what data you can consistantly guess accurately. If you ship rotates at a steady rate forever, then you don't need to send anything (maybe a couple of 'correction packets', to make sure there is no drift), until its rate of turn changes.

Everything is better with Metal.

Sometimes you can extrapolate, if you hide the discrepancy when you actually receive the next packet. My EPIC interpolator does that.
enum Bool { True, False, FileNotFound };
Adding inertia to everything can do wonders like I said. Also no need to snap back technically just interpolate at a faster speed. Then it doesn't look jumpy. But instant rotation changes are odd. One packet they ships at 0 degrees and the next it's at 180. Do these ships move with the mouse? I mean being able to turn instantly is kind of odd.

http://www.sirisian.templarian.com/flash/TURRETTEST.swf

depending, on how your game-play is though I guess. How fast paced is this game? I mean if it doesn't look right at 2 updates a second then something isn't right.
Ah, no, I'm sorry, I misstated. I meant that there was no angular acceleration. Holding right rotates you clockwise at a set angular velocity, so you are in fact turning, but just not speeding up or slowing down as you continue to hold the button.

And it's a pretty fast-paced little game, head-to-head shooter sort of thing.
Quote:Sometimes you can extrapolate, if you hide the discrepancy when you actually receive the next packet. My EPIC interpolator does that.


Well, EPIC does a great job, but if you turn down the updates from 20 per second to 2, it can overshoot pretty badly. Still, I'd be amazed if there exists a system that could get smooth motion out of 2 updates per second (although I was thinking about sending updates with a spread of multiple upcoming positions).

Just to make sure I understand what EPIC does, let me try restating it in English.

Two values are stored at any given time, a snap position and a position to aim for. When a new value comes in, the position at the current time becomes the new snap position, and the new packet's value becomes the new aim position. The aim position is used mostly to calculate the velocity that the position should be moving at on its way to and past the aim position. Thus, the object moves in a series of straight lines, adjusting its direction and velocity once per incoming movement packet. Is that pretty much it?

If that's the case, and if EPIC's algorithm were to be extended to handle the direction the objects are facing, I would posit that it would demonstrate precisely the same problem I described in my original question. Or does it compensate for this somehow?

This topic is closed to new replies.

Advertisement