javascriptnode.jsalgorithmnetwork-programminghermite

Implement hermite interpolation - multiplayer game


I am trying to make a client-server architecture. I am stuck at the interpolation part. Right now, I have a very naive implementation of the interpolation algorithm. I have every player given a position history and whenever I receive a position data for other player from the server I push the position in to that array. Every client frame I use the oldest position history to interpolate to a new position with a constant speed.

// when new position for other player recieved 
p.stateHistory.push(data)

// Every client frame
if(p.stateHistory.length < 1)
            return false

    let deltaPosition = p.stateHistory[0].position.clone().sub(p.clientPosition)
    let direction = Math.atan2(deltaPosition.y, deltaPosition.x)
    let velocity = new Vector2(Math.cos(direction), Math.sin(direction)).scale(30/100)

    let threshold = 10
    if(deltaPosition.magnitude() < threshold) {
        p.clientPosition.x = p.stateHistory[0].position.x
        p.clientPosition.y = p.stateHistory[0].position.y
        p.stateHistory.shift()
    } else {
        p.clientPosition.add(velocity.clone().scale(deltaTime))
    }

I couldn't find way other to interpolate with a constant speed. I came to know about hermite interpolation from gafferongames. But it's sad that the article didn't have anything about its math and its implementation. I tried to go through the wikipedia article on hermite interpolation, but it didn't help. I know nothing about the math behind it. A pseudo code would be appreciated.

What I have been able to do so far: http://client-side-prediction-attempt.herokuapp.com/


Solution

  • Let's say say that your client receives a new position-velocity update at time currentTime. Then, you need to save the current position/velocity, the target position/velocity, the current time, and the time when you expect the next update:

    function updateFromServer(position, velocity) {
        startP = currentPosition; //the current position of the player
        startV = currentVelocity;
        endP   = position;
        endV   = velocity;
        startT = currentTime; //the current time of the game
        endT   = startT + 0.1; //expect the next update in 100 ms
    }
    

    Once you have stored this data, you can do your frame update using interpolation. If you are outside of the [startT, endT] interval, you might just want to continue a uniform motion:

    function frameUpdate(deltaT) {
        if(currentTime > endT)
            //uniform motion
            currentPosition += deltaT * currentVelocity;
        else {
            //cubic Hermite interpolation
            var t = (currentTime - startT) / (endT - startT); //interpolation parameter
            var t2 = t * t;
            var t3 = t2 * t;
            currentPosition = 
                (2 * t3 - 3 * t2 + 1) * startP + 
                (t3 - 2 * t2 + t)     * (endT - startT) * startV + 
                (-2 * t3 + 3 * t2)    * endP   + 
                (t3 - t2)             * (endT - startT) * endV;
            currentVelocity = 1 / (endT - startT) * (
                (6 * t2 - 6 * t)     * startP + 
                (3 * t2 - 4 * t + 1) * (endT - startT) * startV +
                (-6 * t2 + 6 * t)    * endP   +
                (3 * t2 - 2 * t)     * (endT - startT) * endV);
        }
    }
    

    Note that the formulas in this snippet are not valid JavaScript code. They must be translated to whatever library you use.