我正在开发一个浏览器多人游戏,其中每个客户端都插入(线性)由服务器发送的实体帧。它在高帧速率(> 30fps)时看起来不错,但以较低的帧速率抖动(< 30fps)并且冻结并跳跃并且帧速率非常低(< 10fps)。我想降低帧率,并且我知道这是可能的(请参阅以10fps发送更新的Brutal.io)。多人游戏浏览器:线性插值造成抖动和跳跃
这是基本的算法,我使用的:
- 服务器在帧率发送更新(比如,10fps的)
- 客户端渲染游戏在帧率(比如,60fps的)
- 客户端在屏幕上不更新实体直匹配服务器的数据了:这会显得风声鹤唳
- 相反,它使用线性插值函数来消除服务器更新之间的帧
- 以10:60fps为例,客户端将渲染6帧以创建平滑动画
- 它通过测量服务器更新与客户端渲染帧之间的差异(差异)来实现此目的
- 然后得到一个乘法器由潜水客户增量由服务器增量
- 然后,它调用线性插值函数,使用屏幕的位置,服务器的位置,和乘法器,以生成一个新的屏幕位置
该片段不包含特定的代码,但应该足以证明基本概述(请参阅代码中的注释以获取信息):
var serverDelta = 1; // Setting up a variable to store the time between server updates
// Called when the server sends an update (aiming for 10fps)
function onServerUpdate(message) {
serverDelta = Date.now() - lastServerFrame;
}
// Called when the client renders (could be as high as 60fps)
var onClientRender() {
var clientDelta = Date.now() - lastUpdateFrame;
// Describes the multiplier used for the linear interpolation function
var lerpMult = clientDelta/serverDelta;
if (lerpMult > 1) { // Making sure that the screen position doesn't go beyond the server position
lerpMult = 1;
}
lastUpdateFrame = Date.now();
...
// For each entity
// ($x,$y) is position sent by server, (x,y) is current position on screen
entity.x = linearInterpolate(entity.x, entity.$x, lerpMult/2);
entity.y = linearInterpolate(entity.y, entity.$y, lerpMult/2);
}
function linearInterpolate(a, b, f) {
return (a * (1 - f)) + (b * f);
};
如上所述,这会在运动中产生抖动和跳跃。有什么我做错了吗?我将如何使这个动作顺利?
我想明白 - 你怎么知道是什么最后的服务器框架(在插值中)在它发生之前?换句话说,如何在一个值和另一个不知道的值之间进行插值,而不会造成滞后? – clabe45
嗯,好吧,你是说我做这件事的方式是使用前一帧中的增量与当前值进行插值?解决方案是存储“最后的服务器增量”并使用它吗? –
@ clabe45对不起,忘了提及你。见上面^^^。 –