我正在開發一個瀏覽器多人遊戲,其中每個客戶端都插入(線性)由服務器發送的實體幀。它在高幀速率(> 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對不起,忘了提及你。見上面^^^。 –