实现 hermite 插值 - 多人游戏
Implement hermite interpolation - multiplayer game
我正在尝试制作客户端-服务器架构。我被困在插值部分。现在,我有一个非常简单的插值算法实现。我让每个玩家都有一个位置历史记录,每当我从服务器收到其他玩家的位置数据时,我都会将该位置推入该数组。每个客户端框架我使用最旧的位置历史以恒定的速度插值到一个新的位置。
// 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 开始了解 hermite 插值的。但令人遗憾的是,这篇文章没有任何关于它的数学和实现的内容。我试图浏览关于 hermite 插值的维基百科文章,但没有帮助。我对它背后的数学一无所知。伪代码将不胜感激。
到目前为止我能做的事情:http://client-side-prediction-attempt.herokuapp.com/
假设您的客户在时间 currentTime
收到新的仓位速度更新。然后,你需要保存当前position/velocity,目标position/velocity,当前时间,以及你期待下次更新的时间:
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
}
存储此数据后,您可以使用插值法更新帧。如果您在 [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 代码。它们必须翻译成您使用的任何库。
我正在尝试制作客户端-服务器架构。我被困在插值部分。现在,我有一个非常简单的插值算法实现。我让每个玩家都有一个位置历史记录,每当我从服务器收到其他玩家的位置数据时,我都会将该位置推入该数组。每个客户端框架我使用最旧的位置历史以恒定的速度插值到一个新的位置。
// 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 开始了解 hermite 插值的。但令人遗憾的是,这篇文章没有任何关于它的数学和实现的内容。我试图浏览关于 hermite 插值的维基百科文章,但没有帮助。我对它背后的数学一无所知。伪代码将不胜感激。
到目前为止我能做的事情:http://client-side-prediction-attempt.herokuapp.com/
假设您的客户在时间 currentTime
收到新的仓位速度更新。然后,你需要保存当前position/velocity,目标position/velocity,当前时间,以及你期待下次更新的时间:
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
}
存储此数据后,您可以使用插值法更新帧。如果您在 [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 代码。它们必须翻译成您使用的任何库。