快速多人遊戲(3) - Entity插值

原文鏈接:Fast-Paced Multiplayer (Part III): Entity Interpolation

介紹

在系列的第一篇文章中,我們介紹了一種權威服務器的思想還有他在防止玩家作弊方面的優勢。但是直接使用這種技術會引起可玩性和響應性方面的問題。在第二篇文章中,我們提出了一種客戶端預測的方法來處理。


到現在爲止我們提出了一套解決方案,能夠讓玩家在多人遊戲中得到單人遊戲般流暢的體驗,即使是在接入權威服務器並且有一定網絡延遲的情況下。


在這篇文章中,我們將會處理當有別的玩家連入相同的服務器的問題。


服務器時間步長

在前面的文章中,服務器的行爲非常的簡單 - 讀取客戶端的輸入,更新遊戲狀態,然後將結果返回給客戶端。當超過一個客戶端連接的時候,服務器的主循環邏輯就有點不一樣了。

在這種情況下,一些客戶端可能同時快速地發送輸入(比如按方向鍵,移動鼠標或者單擊),每次收到客戶端的請求就更新遊戲,然後再把救過進行廣播, 這樣會消耗大量的CPU和帶寬。


一種好的方式是將玩家的輸入壓到隊列中去而不馬上進行處理,服務器在一定的頻率上進行相對低頻率的更新,比方說沒秒10次。每次更新之間的時長稱爲時間步長,在這裏是100ms。在每次的更新迭代中,所有的未處理的輸入都今次那個處理(可能會比時間步長更小一些,來讓物理更可預測一些)然後新的遊戲狀態就廣播給所有的客戶端。


總的來說,遊戲世界的更新應當在一種可預測的頻率,獨立於玩家的輸入。


處理低頻率的更新

從玩家的角度看,這種方式還是像之前的方法一樣順滑 - 客戶端的預測獨立於更新的延遲,所以對於可預測的狀態更新是沒有問題的。但是,因爲遊戲狀態以一種低頻率進行廣播,這將導致遊戲看上去非常卡頓,可能是100ms更新一次位置。




在客戶端2中看到的客戶端1的情況


根據你開發的遊戲類型,可能有很多方法來處理,通常你的遊戲實體越可預測,越好處理。


航位推

假設你在做一個賽車遊戲。一輛快速開着的車是非常可預測的 - 假設他的速度是100m/s,那麼1s之後,它應當大致在離起始點100m遠的位置。


爲什麼是“大致”?因爲在這一秒中之內,車可能加速一點,也可能減速一點,向右一點或者向右一點 - 這裏說的是一點點。由於車的機動性,車的當前位置總是依賴於它之前的位置,速度和時間。而不是玩家的輸入,換句話說,一輛快速運行的車沒法瞬間180度掉頭。


一個每秒更新10次的服務怎麼來處理呢?客戶端收到每輛車的速度和朝向之後,在接下來的100ms內,它不會受到任何新的信息,但是客戶端還是要進行更新啊。最簡單的方法就是假設車在這100ms內,朝向和加速度都是常量,然後讓這輛車繼續運行,100ms之後,收到更新包之後,再對車的速度進行糾正。

糾正可能很大也可能很小,依賴於很多因素,如果玩家保持直線運行並且不改變車的速度,那麼預測的結果和正式的位置是完全一致的。另一方面,如果玩家撞到什麼東西,預測的位置就完全錯了。

有一點要提一下,航位推的算法可以應用在慢速的情況下 - 比如戰艦。其實這種算法最初就用在海上導航。


Entity插值

有許多情況航位推是沒法處理的 - 對於玩家的方向和速度可以瞬間改變的都不行,比如3D射擊,玩家經常快速跑動,停下,快速轉向等,在這種情況下,航位推算法就非常無力了。因爲位置和速度和前面的數據無關。


你可以選擇在接到服務器的請求的時候直接更新玩家的位置,而客戶端看到的就是網上其他的玩家每100ms跳一下,感覺會非常奇怪。


你現在擁有的是每100ms由服務器傳送過來的權威數據,現在要做的是如何在這100ms內讓網絡角色看起來非常自然,解決問題的關鍵就是將網絡玩家顯示在過去的某個時刻。


假設你在t=1000收到位置信息,你已經在t=900收到了一次位置信息,所以你知道玩家在t=900和t=1000的位置,所以在t=1000到t=1100之間,你只要顯示玩家t=900到t=1000的位置。這種方法,你所顯示的都是玩家的真實數據,只是有100ms的延遲。




客戶端2渲染的是客戶端1的角色過去的位置,利用插值來更新位置


用來插值的t=900和t=1000的數據依賴於遊戲。插值通常都可以處理得很好。如果不是這種方法,你可能需要服務器發送更加詳細的移動信息了 - 比如更多的位置採樣點,或者每10ms發送一次(你不必發十倍的數據 - 因爲你發的微小的位移數據,在這種情況下數據的格式可以很好的優化一下)。


當使用這種技術的時候,每一個玩家都和遊戲世界有一點點不同步,因爲每個玩家看到自己的世界是當前的,但是其他的玩家都是過去的。但即使是快速的遊戲,這100ms的延遲都不是那麼明顯。


有一種情況除外 - 當你需要時間和空間的準確性的時候,比如一個玩家射擊另一個玩家的時候,因爲其他的玩家都是存在於過去的某個時候,你的瞄準其實是有100ms的延遲的 - 也就是說,你設計的目標是100ms的某個目標! 這個問題我們下一篇會進行討論。


總結

在權威服務器的環境中,有着不確定的服務器更新和網絡延遲,在這種情況下你還要給玩家平滑的移動。在第二篇中,我們展示了一種客戶端預測和服務器調和的技術,來實現實時的角色控制,這樣的方案讓玩家能夠得到即時的反饋,移除了致命的延遲。

其他玩家的同步還是一個問題,但是,在這篇文章中,我們提出了兩種解決方案。

第一種是航位推技術,這種模擬需要entity的位置能夠通過前一個時候的位置,速度,加速度來推算出來,當不滿足這種情況的時候,航位推就沒用了。

第二種是插值技術,不預測將來的位置,只是使用服務器傳來的數據,這種就會造成顯示的entity總是過去的某個時刻。最後的結果就是玩家的角色總是當前時刻,而其他看到的entity都是過去的某個時刻,這種情況可以產生一種難以置信的無縫體驗。

但是,當遊戲需要高速離散的準確性的時候,比如射擊或者移動物體,美景就破滅了:你看其他玩家的位置和服務器的位置不一致,別的玩家看你的位置也不是正確的,這樣爆頭就不可能發生了!很多遊戲都有爆頭這一說,我們將在下面的文章中來討論這個問題。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章