Multiplayer Game - Client Interpolation Calculation?
Asked Answered
A

3

24

I am creating a Multiplayer game using socket io in javascript. The game works perfectly at the moment aside from the client interpolation. Right now, when I get a packet from the server, I simply set the clients position to the position sent by the server. Here is what I have tried to do:

getServerInfo(packet) {
     var otherPlayer = players[packet.id]; // GET PLAYER
     otherPlayer.setTarget(packet.x, packet.y); // SET TARGET TO MOVE TO
     ...
}

So I set the players Target position. And then in the Players Update method I simply did this:

var update = function(delta) {
    if (x != target.x || y != target.y){
        var direction = Math.atan2((target.y - y), (target.x - x));
        x += (delta* speed) * Math.cos(direction);
        y += (delta* speed) * Math.sin(direction);
        var dist = Math.sqrt((x - target.x) * (x - target.x) + (y - target.y)
                * (y - target.y));
        if (dist < treshhold){
            x = target.x;
            y = target.y;
        }
    }   
}

This basically moves the player in the direction of the target at a fixed speed. The issue is that the player arrives at the target either before or after the next information arrives from the server.

Edit: I have just read Gabriel Bambettas Article on this subject, and he mentions this:

Say you receive position data at t = 1000. You already had received data at t = 900, so you know where the player was at t = 900 and t = 1000. So, from t = 1000 and t = 1100, you show what the other player did from t = 900 to t = 1000. This way you’re always showing the user actual movement data, except you’re showing it 100 ms “late”.

This again assumed that it is exactly 100ms late. If your ping varies a lot, this will not work.

Would you be able to provide some pseudo code so I can get an Idea of how to do this?

I have found this question online here. But none of the answers provide an example of how to do it, only suggestions.

Allness answered 19/9, 2015 at 23:5 Comment(1)
I am running into this issue as well, with jitter in my game. Were you able to solve this using the answer with the checkmark? Or were there other factors at play that helped you solve this problem? If so, could you please provide some sort of example implementation? Thank you.Enfeeble
H
7

I'm completely fresh to multiplayer game client/server architecture and algorithms, however in reading this question the first thing that came to mind was implementing second-order (or higher) Kalman filters on the relevant variables for each player.

Specifically, the Kalman prediction steps which are much better than simple dead-reckoning. Also the fact that Kalman prediction and update steps work somewhat as weighted or optimal interpolators. And futhermore, the dynamics of players could be encoded directly rather than playing around with abstracted parameterizations used in other methods.

Meanwhile, a quick search led me to this:

An improvement of dead reckoning algorithm using kalman filter for minimizing network traffic of 3d on-line games

The abstract:

Online 3D games require efficient and fast user interaction support over network, and the networking support is usually implemented using network game engine. The network game engine should minimize the network delay and mitigate the network traffic congestion. To minimize the network traffic between game users, a client-based prediction (dead reckoning algorithm) is used. Each game entity uses the algorithm to estimates its own movement (also other entities' movement), and when the estimation error is over threshold, the entity sends the UPDATE (including position, velocity, etc) packet to other entities. As the estimation accuracy is increased, each entity can minimize the transmission of the UPDATE packet. To improve the prediction accuracy of dead reckoning algorithm, we propose the Kalman filter based dead reckoning approach. To show real demonstration, we use a popular network game (BZFlag), and improve the game optimized dead reckoning algorithm using Kalman filter. We improve the prediction accuracy and reduce the network traffic by 12 percents.

Might seem wordy and like a whole new problem to learn what it's all about... and discrete state-space for that matter.

Briefly, I'd say a Kalman filter is a filter that takes into account uncertainty, which is what you've got here. It normally works on measurement uncertainty at a known sample rate, but it could be re-tooled to work with uncertainty in measurement period/phase.

The idea being that in lieu of a proper measurement, you'd simply update with the kalman predictions. The tactic is similar to target tracking applications.

I was recommended them on stackexchange myself - took about a week to figure out how they were relevant but I've since implemented them successfully in vision processing work.

(...it's making me want to experiment with your problem now !)

As I wanted more direct control over the filter, I copied someone else's roll-your-own implementation of a Kalman filter in matlab into openCV (in C++):

void Marker::kalmanPredict(){

    //Prediction for state vector 
    Xx = A * Xx;
    Xy = A * Xy;
    //and covariance
    Px = A * Px * A.t() + Q;
    Py = A * Py * A.t() + Q;
}

void Marker::kalmanUpdate(Point2d& measuredPosition){

    //Kalman gain K:
    Mat tempINVx = Mat(2, 2, CV_64F);
    Mat tempINVy = Mat(2, 2, CV_64F);
    tempINVx = C*Px*C.t() + R;
    tempINVy = C*Py*C.t() + R;
    Kx = Px*C.t() * tempINVx.inv(DECOMP_CHOLESKY);
    Ky = Py*C.t() * tempINVy.inv(DECOMP_CHOLESKY);

    //Estimate of velocity
    //units are pixels.s^-1
    Point2d measuredVelocity = Point2d(measuredPosition.x - Xx.at<double>(0), measuredPosition.y - Xy.at<double>(0));  
    Mat zx = (Mat_<double>(2,1) << measuredPosition.x, measuredVelocity.x);
    Mat zy = (Mat_<double>(2,1) << measuredPosition.y, measuredVelocity.y);

    //kalman correction based on position measurement and velocity estimate:
    Xx = Xx + Kx*(zx - C*Xx);
    Xy = Xy + Ky*(zy - C*Xy);
    //and covariance again
    Px = Px - Kx*C*Px;
    Py = Py - Ky*C*Py;
}

I don't expect you to be able to use this directly though, but if anyone comes across it and understand what 'A', 'P', 'Q' and 'C' are in state-space (hint hint, state-space understanding is a pre-req here) they'll likely see how connect the dots.

(both matlab and openCV have their own Kalman filter implementations included by the way...)

Helmand answered 22/9, 2015 at 3:22 Comment(11)
Thank you for the suggestion. I will have to do research on this before attempting to implement this into my game. From what I have read it seems a bit excessive for what is seemly such a simple task.Allness
@TastyLemons Careful, not to let the simplicity of the problem statement detract from a solution ! :) I agree though, it would take a bit of learning and conceptual understanding (regarding state-space for the most part), but it would appear to be where the technology is at. The relevant algorithmic part of my eventual implementation (in openCV) was only 30 lines or so.Helmand
Wish I could make it easier - try this: au.mathworks.com/videos/… - imagine the 'box' is a lag in client server comms ... As in as the ball goes behind it, it's the same as a box getting in the way of comms (heh, make sense?)Helmand
After watching this I don't feel like I can use this for the game. Because players are always changing direction and speed. So predictive behaviour like this wont work.Allness
What you're decribeing wont work is called 'dead-reckoning' which is what the work in the paper specifically was developed to improve on. Dead reckoning is actually pretty much what your third code snippet implements... Regardless, prediction is only used in lieu of actual measurement, and Kalman filters keep track of sample to sample variance, in that the dynamic model is dynamic.Helmand
Let us continue this discussion in chat.Allness
I'll argue against my own self-interest here: if you are trying to use past updates to come up with an estimate of where something is at a later time, what you are doing is by definition a prediction and there's just no way around that. However: this answer is not actually simpler than mine. I just provided enough detail to actually implement the suggestion.Luce
I never suggested it was simpler? In fact I agree, yours is simpler ... Also they call it the Kalman prediction step because it is a prediction, so I'll agree with you there too. Hrrrrm, the OP states "objects in the game will change direction constantly"and "players are always changing direction and speed" as if this is something we're unaware of ... I'm starting to get waryHelmand
Im sorry guys. I just wanted some sample code so I can get an idea of this. You are way ahead of me on this topic.Allness
@Lamar Latrell: I can see now how the last sentence of that comment might be taken as snark directed at you. It wasn't intended that way! It also doesn't make a lot of sense now that I've edited out my linear algebra and you've added sample code.Luce
@Lorehead, I figured as much, online communications can be tricky to navigate sometimes (if it means anything that was actually my up-vote on your comment :) I've realised that it's such a complex topic (a Kalman implementation for instance, and higher order interpolations like yours) that any one answer will fail to cover all the bases, my code was added just to show that in the end it's just additions and multiplications (linear algebra!). But yeah.. Personally I think stripping down on detail in an answer will dilute the reality here, it's a complex problem, that calls for a complex answer.Helmand
L
2

This question is being left open with a request for more detail, so I’ll try to fill in the gaps of Patrick Klug’s answer. He suggested, reasonably, that you transmit both the current position and the current velocity at each time point.

Since two position and two velocity measurements give a system of four equations, it enables us to solve for a system of four unknowns, namely a cubic spline (which has four coefficients, a, b, c and d). In order for this spline to be smooth, the first and second derivatives (velocity and acceleration) should be equal at the endpoints. There are two standard, equivalent ways of calculating this: Hermite splines (https://en.wikipedia.org/wiki/Cubic_Hermite_spline) and Bézier splines (http://mathfaculty.fullerton.edu/mathews/n2003/BezierCurveMod.html). For a two-dimensional problem such as this, I suggested separating variables and finding splines for both x and y based on the tangent data in the updates, which is called a clamped piecewise cubic Hermite spline. This has several advantages over the splines in the link above, such as cardinal splines, which do not take advantage of that information. The locations and velocities at the control points will match, you can interpolate up to the last update rather than the one before, and you can apply this method just as easily to polar coordinates if the game world is inherently polar like Space wars. (Another approach sometimes used for periodic data is to perform a FFT and do trigonometric interpolation in the frequency domain, but that doesn’t sound applicable here.)

What originally appeared here was a derivation of the Hermite spline using linear algebra in a somewhat unusual way that (unless I made a mistake entering it) would have worked. However, the comments convinced me it would be more helpful to give the standard names for what I was talking about. If you are interested in the mathematical details of how and why this works, this is a better explanation: https://math.stackexchange.com/questions/62360/natural-cubic-splines-vs-piecewise-hermite-splines

A better algorithm than the one I gave is to represent the sample points and first derivatives as a tridiagonal matrix that, multiplied by a column vector of coefficients, produces the boundary conditions, and solve for the coefficients. An alternative is to add control points to a Bézier curve where the tangent lines at the sampled points intersect and on the tangent lines at the endpoints. Both methods produce the same, unique, smooth cubic spline.

One situation you might be able to avoid if you were choosing the points rather than receiving updates is if you get a bad sample of points. You can’t, for example, intersect parallel tangent lines, or tell what happened if it’s back in the same place with a nonzero first derivative. You’d never choose those points for a piecewise spline, but you might get them if an object made a swerve between updates.

If my computer weren’t broken right now, here is where I would put fancy graphics like the ones I posted to TeX.SX. Unfortunately, I have to bow out of those for now.

Is this better than straight linear interpolation? Definitely: linear interpolation will get you straight- line paths, quadratic splines won't be smooth, and higher-order polynomials will likely be overfitted. Cubic splines are the standard way to solve that problem.

Are they better for extrapolation, where you try to predict where a game object will go? Possibly not: this way, you’re assuming that a player who’s accelerating will keep accelerating, rather than that they will immediately stop accelerating, and that could put you much further off. However, the time between updates should be short, so you shouldn’t get too far off.

Finally, you might make things a lot easier on yourself by programming in a bit more conservation of momentum. If there’s a limit to how quickly objects can turn, accelerate or decelerate, their paths will not be able to diverge as much from where you predict based on their last positions and velocities.

Luce answered 22/9, 2015 at 3:23 Comment(15)
This seems excessively complex. I am not sure what each of these values represents in regards to calculating the movement of the game objects. Do you mind generalizing/simplifying your answer a little?Allness
This is more like Dead Reckoning if I understand correctly. And objects in the game will change direction constantly, so I don't think this would be the best way right?Allness
If objects that are slowing down are likely to keep slowing down, and those that are accelerating are likely to keep accelerating, this will work better. If objects do the opposite, it will do worse. If something braking and turning to the right is likely to keep doing the same thing, you might have more success predicting r and theta rather than x and y. If objects are always changing direction unpredictably, you can't predict them no matter what.Luce
Yeah i cannot predict them at all. All I want to do is smooth their movement from point1 to point2 before the next target is set.Allness
I made what would have been my response the new final paragraph of my answer.Luce
But interpolated cubic splines are pretty much the standard way to generate a smooth path from a few known points. I have not actually tried them for this purpose, but I know the theory.Luce
This answer suggests interpolating a cubic curve between two consecutive time moments by using positions and velocities. Indeed, it would be better if it was concentrated on the idea, not on the implementations details. A picture would be cool too =) Also, it is not a good idea to use BLAS here, because the system is very small. Just solve it with any convenient tool you have, do not mess with HPC computing.Hallowmas
By the way, it is trivial to interpolate cubic curve by end points. Get a cubic Bezier curve with control points A, A + Ut/3, B - Vt/3, B, where A,B are positions and U,V are corresponding velocities, and t is time difference. So I suggest removing all the hard work with matrices and equations =)Hallowmas
What I'm describing is a Hermite spline, which is equivalent to a Bézier spline. However, you're right. Especially since I took out the part where I actually solved it, I should just identify it by name and link to the finished algorithm. Still, solving from first principles was fun.Luce
Okay. Rewrote to provide useful references to information about cubic splines rather than a lot of math.Luce
Give me a day or so to do research on all this and I will try to implement this into javascript. Thank you for your help.Allness
"If objects are always changing direction unpredictably, you can't predict them no matter what." You can go deeper and deeper in the order of a Kalman filter and get predictions that appear magical (of course they aren't as you know). 3rd order follows accel, 4th order, jerk and so on ... But the deeper you go the more reliant the system is on the sample frequency, so it's perhaps not as simple as I'm making it sound. Anyways, looks like the OP found a solution in your answer, which is good :)Helmand
I honestly have never worked with Kalman filters, so I learned something from those answers. If he had been more interested in extrapolation than interpolation, that might have been the way to go. I'll tweak my answer a bit to provide a bit more detail on clamped boundary conditions.Luce
And updated with a link to a prettier explanation of the linear algebra and a little more information.Luce
Cleaned up the wording about possible sources of error. The problem is not that you won’t, numerically, get some answer.Luce
S
1

Depending on your game you might want to prefer smooth player movement over super-precise location. If so, then I'd suggest to aim for 'eventual consistency'. I think your idea of keeping 'real' and 'simulated' data-points is a good one. Just make sure that from time to time you force the simulated to converge with the real, otherwise the gap will get too big.

Regarding your concern about different movement speed I'd suggest you include the current velocity and direction of the player in addition to the current position in your packet. This will enable you to more smoothly predict where the player would be based on your own framerate/update timing.

Essentially you would calculate the current simulated velocity and direction taking into account the last simulated location and velocity as well as last known location and velocity (put more emphasis on the second) and then simulate new position based on that.

If the gap between simulated and known gets too big, just put more emphasis on the known location and the otherPlayer will catch up quicker.

Sheasheaf answered 21/9, 2015 at 0:0 Comment(5)
Could you provide some code sample of this? The problem with sending the speed along with the packet, is that when the other player suddenly stops moving, their speed is set to 0, which will mean he will stop moving on your end much sooner than he did on his end, causing him to stop at an incorrect location.Allness
I'm not following your concern. If the velocity is 0 you already know the precise location in the paket as well so then you can simply adjust your velocity to match the location with whatever speed-limit feels right.Sheasheaf
So you are suggesting that I send the players x,y,speed,direction and then lerp them to that x,y based on this speed. And when a new packet comes in, simply update the target to the new x,y and use the new speed to move? And this will work smoothly? Thanks for your response Patrick. Could you give me a pseudo code sample, so I can get an Idea of what you mean?Allness
You may want to look into Kalman filter as a more advanced version of this, though it may be excess or less than ideal for this purpose. Udacity has a decent section on them.Bevins
@TastyLemons, using a spline means you fit a smooth curve on your current discrete trajectory. Of course, that makes it smooth.Otterburn

© 2022 - 2024 — McMap. All rights reserved.