Реализация интерполяции Эрмита - многопользовательская игра - PullRequest
1 голос
/ 22 марта 2019

Я пытаюсь сделать клиент-серверную архитектуру. Я застрял в интерполяционной части. Прямо сейчас у меня очень наивная реализация алгоритма интерполяции. У меня есть каждый игрок, у которого есть история позиций, и всякий раз, когда я получаю данные позиции для другого игрока с сервера, я помещаю позицию в этот массив. В каждом кадре клиента я использую самую старую историю позиций для интерполяции на новую позицию с постоянной скоростью.

// 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))
    }

Я не мог найти другой способ интерполировать с постоянной скоростью. Я узнал об интерполяции эрмитов из gafferongames. Но грустно, что статья не имела ничего о ее математике и ее реализации. Я пытался просмотреть статью в Википедии об интерполяции Эрмита, но это не помогло. Я ничего не знаю о математике за этим. Был бы признателен псевдокод.

Что я смог сделать до сих пор: http://client -side-prediction-attempt.herokuapp.com /

1 Ответ

0 голосов
/ 23 марта 2019

Допустим, ваш клиент получает новое обновление скорости позиции в момент времени currentTime.Затем вам нужно сохранить текущую позицию / скорость, целевую позицию / скорость, текущее время и время, когда вы ожидаете следующее обновление:

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

После того, как вы сохранили эти данные, вы можетеобновите кадр, используя интерполяцию.Если вы находитесь за пределами интервала [startT, endT], вы можете просто продолжить равномерное движение:

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);
    }
}

Обратите внимание, что формулы в этом фрагменте не являются допустимым кодом JavaScript.Они должны быть переведены в любую библиотеку, которую вы используете.

...