幀同步遊戲的設計

大囚長發表於2019-02-02

轉自:
https://blog.csdn.net/ad88282284/article/details/52864011

從單機遊戲到網路遊戲

單機遊戲,這裡指即時的動作類遊戲,玩家輸入操作,通過終端運算而進行的遊戲。加入了多人網路以後,玩家的輸入不僅僅只是在本地的終端上運算,還會通過網路同步,使多人可以在同一個虛擬環境中同時遊戲。由此,網路多人快節奏的動作遊戲帶來了新的問題:一致性,響應性,頻寬,延遲。網路遊戲的實時PVP就是為了平衡這四點的要素。

幀同步的引入

幀同步應該是引入多人網路以後,能想到最直接 的同步方式,在理想狀態下,是合適的解決方案。而現實是,幀同步需要傳送大量的幀資料來驅動遊戲邏輯,需要客戶端能在一段時間保持網路穩定(低延遲,少量的網路抖動)。此外,還有狀態同步技術,幀同步是把玩家的動作直接同步到其他玩家的終端上,通過確定性的運算達到同步效果,而狀態同步是所有客戶端的動作傳送到伺服器,由伺服器計算並把最終狀態廣播下發。網上有大量的資料對這兩種技術進行對比,下面只對幀同步的技術做講述。

幀同步的原理

瞭解幀同步技術,不妨可以參考下DOOM/QUAKE I/II/III 網路模型的演化,約翰·卡馬克為FPS的網路同步寫下了原型,後面的版本又在這基礎上做出了眾多改良版本。

幀同步技術最重要的基礎概念:

相同的輸入+相同的時機=相同的顯示
意思是每個客戶端接受的輸入是相同的,執行的邏輯幀也是一樣的,那麼結果也是同步一致的。為了跟每個機器執行的快慢無關,每個邏輯幀為固定幀數固定時長,遊戲當中的實體都是按照這種設定運算,因此移動、碰撞等都能算出相同的結果。而渲染幀(一般為30到60幀),則是根據邏輯幀(10到20幀)去插值,得到一個“平滑”的展示。邏輯幀實際是是由一個個定時下發的“網路幀”來驅動,而渲染幀則由本地CPU的update驅動,渲染幀只是邏輯幀無限逼近(插值),如果邏輯幀突然中斷,則遊戲就會卡在那一幀狀態,這就是lockstep的由來。
為了保證遊戲同步執行的一致性,程式碼必須按照lockstep的方式組織運算,不依賴本地客戶端的幀率,時間或者隨機數。理想狀態下,每個“網路幀”被及時接收,客戶端渲染幀都能滿幀運算,遊戲就像播放電影一樣。但在網路遊戲中,各個客戶端的硬體和網路情況都不一樣,可能會導致客戶端收到“過去時間”裡的一堆網路幀,因此,必須要有處理這些堆積起來的網路資料的能力。最簡單的做法是加速播放(快進),根據堆積的量計算出加速比率,以此快速地執行邏輯幀,儘快地追上最新的實時幀。同時,在加速的過程中,可以考慮丟棄使用者的操作,因為玩家看到的是“過去”的狀態,此時進行控制打擊是沒有意義的。另外一種處理方式是,直接運算直至追上最新的網路幀,這樣會直接閃現到“最新”的狀態,玩家可以馬上操作。比較建議採用快進的手段,這種方式可以讓玩家感受到相對自然的遊戲畫面。這一基礎特性也用於支援後面的斷線重連。

幀同步的響應性

對於實時PVP的遊戲來說,手感流暢的角色控制體驗很重要。玩家的輸入往往在幾十分之一秒內,就開始顯示變化,而在幀同步中,玩家的輸入傳送到網路,下一個網路幀操作回來時儘快處理並顯示 ,當網路不穩定時,常常會時快時慢,非常難以預測輸入動作後,角色會在什麼時候起反應。要解決這個問題,可以參考下傳輸語音業務的做法,在接收網路資料時,不立刻處理,而是給所有的操作增加一個固定的延遲,在延遲的時間內儘可能收集更多的網路包,然後按固定的時間去播放(運算)。這種做法相當於建立了一個網路緩衝區,平滑了因為網路抖動而時快時慢的資料包。這裡新增的固定延遲可以按照玩家所在的網路延遲來設定,可以動態地取一個連續平穩(避免抖動)的值,可以使用累計或抽樣的加權平均來獲取延遲。玩家發出的操作只要在固定延遲內接收,遊戲就可以流暢執行,網路的抖動已經被間隔相等的邏輯幀抹平了。

TCP還是UDP,這是一個問題

保證了邏輯運算的一致性以及邏輯幀的平滑加速,基本上可以動手把一個單機遊戲改成多人聯機遊戲了,在區域網執行勉強還能接受,可惜,我們做的是網際網路上的遊戲。接下來了解一下行動網路的延遲情況。首先是TCP,保證了包序,丟包自動重傳,看起來就是我們想要的拼圖,並且已經有人幫我們實現了,而且還幫老闆省了一大筆錢。誠然,可靠的傳輸協議非常誘人,並且也有不少成功的例子,且再權衡下缺點再做決定。TCP是基於重傳來保證可靠性,如果IP包丟包,TCP協議需要等待至少2個往返時延才會重新傳送這個資料包,丟包嚴重甚至會斷線,一旦斷線,則觸發斷線重連流程。看看下面一組資料。

這是騰訊一款以忍者格鬥為題材的ACT手遊給出來的資料,可以看到在各種網路情形下,UDP的表現(延遲分佈)基本上都優於TCP。
那麼到UDP,非面向連線的傳輸協議,沒有自動重傳,沒有擁塞控制,不能保證包序,甚至不能保證可到達,只保證了資料包完整的基礎特性。優點是延遲小、資料傳輸效率高、資源開銷小,如果用來作為網路遊戲的傳輸方案,需要在應用層定製更多適用於網遊的特性。在UDP基礎上定製一個應用層的協議,難度比較大。基於UDP也有一個通用的解決方案UDT,保證了可靠性和包序,但是跟TCP類似的,UDT也是基於超時重傳的方式保證可靠。下面我想把一些專用定製的方案拿出來討論。
首先,幀同步需要每幀廣播資料,廣播的頻率非常高,這要求每次廣播的資料要足夠小,最好每個網路幀在一個MTU以下,這樣可以避免在IP層分片,降低延遲,網際網路的MTU標準為576位元組,有效載荷長度控制在(576-8-20)548位元組以內。為了儘量避免重傳,遊戲裡面可以用冗餘的方式——每個幀資料包實際包含了過去2幀的資料,也就是每次發3幀的資料來對抗丟包。三個包裡面只要有一個包沒丟,就不影響遊戲。另外,定製的方案還需要有一個請求“下載”丟失幀的特性,以防止連續3個包全丟的情況。對於“下載”特性,則可以考慮使用TCP。這是全冗餘的做法,缺點是會導致流量增加2倍。還有一種動態冗餘演算法,根據客戶端的丟包狀況動態調整冗餘倍數,上面介紹的那款ACT遊戲就是用了這種方法,本質上還是用流量換速度。
接發包速率對一款PVP競技型的商業遊戲來說至關重要,目前還只是學習到皮毛,以後深入瞭解後再補充。除此之外,後續還需要伺服器介入,解決斷線重連和反作弊等問題,先寫到這裡。

相關文章