FPS游戲原理漫談:玩家延時與服務器同步

>>>  創業先鋒 眾人拾柴火焰高  >>> 簡體     傳統


  在在FPS游戲中玩家延時都不一樣的情況下是怎樣做到游戲的同步?知友“周愷華”對此給出較為充實的回答,有興趣了解這方面知識的玩家可以通過下面的回答來一窺究竟:

  聲明:下面會大量使用CSGO作為例子,因為Valve在多人游戲的網絡通信方面做得較好,可以當做一個典型來分析。

  多人競技游戲中客戶端和服務器的互動

  游戲中所有的邏輯判定都是由服務器完成的,客戶端只負責發送請求和接收服務器的反饋,并把反饋具象化。拿CSGO做例子,玩家A拿著AK瞄準了玩家B的頭開了一槍,那么玩家A的客戶端會向服務器發送一個數據包,里面包含了誰(玩家A)拿著什么武器(AK)從什么位置(玩家A在地圖上的坐標)向什么方向(角度)開了一槍。服務器收到后進行判定,這一槍的傷害會經過玩家B的頭部模型,判定為爆頭傷害,數值為XX,判定玩家B死亡。服務器再向所有玩家的客戶端通信,更新當前游戲狀態,其中包括玩家A用AK爆頭擊殺了玩家B,也會包括其他信息,比如玩家們的位置等等。玩家A收到通信后顯示擊殺了玩家B,玩家B則會收到被擊殺的信息。

  接著講一個概念,叫服務器的通信頻率(tick rate)。事實上服務器不是百分百實時地向玩家通信來更新游戲狀態的,那樣需要的計算量很大,同時對網絡帶寬的要求也會高的不現實,因此服務器會以一定的頻率來進行通信。

  CSGO在娛樂模式下通常采用60Hz的頻率,也就是說每過1/60秒玩家的客戶端就會收到一次新的信息。如果回到上面那個例子,那么實際情況應該是:玩家A拿著AK瞄準玩家B的頭開一槍,你的客戶端會向服務器發送一個數據包,服務器接收后進行判定。判定完成后等待至下一次通信,再向所有玩家更新游戲狀態。也就是說游戲過程其實是一個離散的過程而非連續過程。


  如果玩家的Ping很大,服務器會怎么辦?

  上面的例子都假設客戶端和服務器之間的延遲無窮小,那么當玩家Ping很大的時候會發生什么的呢?

  假設玩家A與服務器之間存在100ms的延遲(單向,往返則是200ms),其他玩家的延遲忽略不計,服務器的通信頻率足夠大(頻率不夠大還會造成其他很嚴重的問題,這個放在后面講)。玩家A在某一刻向服務器發送了一個請求(比如向前走),那么這個請求會在100ms之后到達服務器,服務器判定后返回結果,再經過100ms你的客戶端會收到確認,服務器已經把你的位置向前移動了若干距離。假設客戶端在沒有收到任何服務器的更新前畫面都不會變化,那么在這200ms內你就會覺得游戲“卡頓”。

  實際上很多游戲里中你會在這200ms里看到你自己是在向前走,其實那只是客戶端“擅自”在繪制你前進的樣子,這是一種延遲補償策略,稱為“客戶端預測法”。即客戶端能夠大致預測游戲未來的走向,因此在接收到服務器更新前會把預測到的畫面先繪制出來(比如移動、武器的開火效果、彈藥計數的變化等)。客戶端收到服務器通信后如果數據有出入則立刻糾正為服務器提供的數據。因此在延遲很大的時候玩家會發現“明明往前走了過了一會又瞬移回到之前的位置”的原因,或者是“明明開了好幾槍而且也都顯示了但過了一會彈藥計數只減少了一點點”。

  既然扯到這里了那就認真的講下延遲補償策略(lag compensation),一般來講補償策略分服務器端和客戶端兩類,上面提到的預測法屬于客戶端一類,其他的客戶端策略還有插幀法。所謂插幀法就是客戶端會記錄之前一次從服務器收到的信息,然后在接受到下一次通信的時候不立刻更新游戲畫面,而是逐漸的更新畫面(比如兩次通信間玩家B移動了10單位距離,客戶端會繪制玩家B以一定的速度移動了這10單位距離,而非立刻繪制玩家B瞬間移動了10單位距離)。插幀法的問題在于如果玩家并未沿直線運動且其直線路徑中有本應不能通過的物體存在時(比如繞過一堵墻),客戶端會繪制出該玩家穿墻而非繞過去的動作。

  服務器端處理延時同步常用的策略

  1、“眼不見為凈”法,服務器不去補償玩家的延遲是一個合理的做法,特別是當游戲內進行的事件非常多(想想《行星邊際2》里面千人同圖混戰的情形)。浪費寶貴的服務器資源去補償個別玩家的延遲是不明智的。這個策略的缺點很明顯,就是玩家有可能會對游戲體驗不滿意。

  2、“倒帶”法,采用倒帶法的服務器會記錄剛剛過去一段時間內(比如0.5秒)游戲內的所有信息。當一個有延遲的玩家(比如200ms)向服務器發送一個請求,那么服務器在處理這個請求的時候會調取0.2秒前游戲的狀態然后進行判定,在把判定結果對所有客戶端進行同步,如此一來該玩家的操作雖然有延遲但也能與他/她所看見的畫面一致。該策略的最大問題在于它讓不同延遲之間的玩家被迫體驗較大的延遲。舉個例子,假設游戲里擊殺時間(TTK)足夠小,玩家A(10ms延遲)和玩家B(延遲200ms)對射,兩人都是空血(一次攻擊即死),A比B先開火(時間差很小,比如50ms)。玩家A的次攻擊很快(10ms后)就得到了處理并記錄在服務器中,玩家B被判死亡。然而在200ms后玩家B的請求到達,服務器倒帶0.2秒,此時玩家AB都未死亡,因此玩家B的攻擊有效,玩家A也被判定為死亡。如果沒有延遲,那么服務器應該會判定玩家B死亡,因此玩家B將無法攻擊,玩家A應該存活。換句話說采用倒帶法的服務器里如果有一個延遲很大的玩家將會拖累其他低延遲玩家的游戲體驗。


文 / 周愷華 知乎


GameRes游資網 2015-08-23 08:47:48

[新一篇] 《每周一玩》第二十八期:全新西游夢 經典再啟航

[舊一篇] 小議關于游戲設計的各種理論是否有用
回頂部
寫評論


評論集


暫無評論。

稱謂:

内容:

驗證:


返回列表