手機格鬥網遊該如何避免延遲?


謝邀,2005-2007間我寫過一系列遊戲同步的文章,供參:

  • 幀間同步模式: 幀鎖定同步演算法 (2007):

  • 玩法規避模式:網路遊戲同步法則 (2005) 最好給您們策劃看這篇,玩法規避

  • 預測插值模式:影子跟隨演算法 (2007) FPS, 賽車

  • 提高傳輸速度: 快速可靠傳輸協議 (2012)基於UDP的快速可靠協議。

摘錄第一篇文章如下,我寫這篇文章是基於我 2005-2006年開發的東西來說的,當時國內公網質量比國外差很多(公網很多平均100ms,120ms的RTT),所以我文中引用了很多 100ms。這個情況在2009年以後已經好了很多(60ms的rtt)。到了2012年以後,公網平均 RTT已經降低到平均 40ms-50ms,省內平均10ms以內了,如果全國多布點以及區別電信聯通的話,平均延遲能控制在20ms以內,延遲基本接近國外水平(當然帶寬還差很多),比我當年文章中提到的網路情況好了不少:

&" dw="1033" dh="505" class="origin_image zh-lightbox-thumb lazy" w="1033" data-original="https://pic3.zhimg.com/8daa7525753ce2a6996574a4836365bb_r.jpg" data-actualsrc="//i1.wp.com/pic3.zhimg.com/50/8daa7525753ce2a6996574a4836365bb_hd.jpg">

-------------------------------------

正文:

早期 RTS,XBOX360 LIVE遊戲常用同步策略是什麼?格鬥遊戲多人聯機如何保證流暢性和一致性?如何才能像單機遊戲一樣編寫網遊?

演算法概念

該演算法普遍要求網速RTT要在100ms以內,一般人數不超過8人,在這樣的情況下,可以像單機遊戲一樣編寫網路遊戲。所有客戶端任意時刻邏輯都是統一的,缺點是一個人卡機,所有人等待。

1.客戶端定時(比如每五幀)上傳控制信息。

2.伺服器收到所有控制信息後廣播給所有客戶。

3.客戶端用伺服器發來的更新消息中的控制信息進行遊戲。

4.如果客戶端進行到下一個關鍵幀(5幀後)時沒有收到伺服器的更新消息則等待。

5.如果客戶端進行到下一個關鍵幀時已經接收到了伺服器的更新消息,則將上面的數據用於遊戲,並採集當前滑鼠鍵盤輸入發送給伺服器,同時繼續進行下去。

6.服務端採集到所有數據後再次發送下一個關鍵幀更新消息。

這個等待關鍵幀更新數據的過程稱為「幀鎖定」

應用案例:大部分RTS遊戲,街霸II(xbox360),Callus模擬器。

演算法流程

客戶端邏輯:

  1. 判斷當前幀F是否關鍵幀K1:如果不是跳轉(7)。

  2. 如果是關鍵幀,則察看有沒有K1的UPDATE數據,如果沒有的話重複2等待。

  3. 採集當前K1的輸入作為CTRL數據與K1編號一起發送給伺服器

  4. 從UPDATE K1中得到下一個關鍵幀的號碼K2以及到下一個關鍵幀之間的輸入數據I。

  5. 從這個關鍵幀到下 一個關鍵幀K2之間的虛擬輸入都用I。

  6. 令K1 = K2。

  7. 執行該幀邏輯

  8. 跳轉(1)

服務端邏輯:

  1. 收集所有客戶端本關鍵幀K1的CTRL數據(Ctrl-K)等待知道收集完成所有的CTRL-K。

  2. 根據所有CTRL-K,計算下一個關鍵幀K2的Update,計算再下一個關鍵幀的編號K3。

  3. 將Update發送給所有客戶端

  4. 令K1=K2

  5. 跳轉(1)

&" dw="697" dh="428" class="origin_image zh-lightbox-thumb lazy" w="697" data-original="https://pic4.zhimg.com/e4e6a22a7aee97a407e23dd90d2f59d7_r.jpg" data-actualsrc="//i1.wp.com/pic4.zhimg.com/50/e4e6a22a7aee97a407e23dd90d2f59d7_hd.jpg">

伺服器根據所有客戶端的最大RTT,平滑計算下一個關鍵幀的編號,讓延遲根據網路情況自動調整。

演算法演示

我根據該演算法將街機模擬器修改出了一個可用於多人對戰的版本,早期有一個叫做kaillera的東西,可以幫助模擬器實現多人聯機,但是並沒有作幀鎖定,只是簡單將鍵盤消息進行收集廣播而已,後來Capcom在PSP和360上都出過街霸的聯網版本,但是聯網效果不理想。這個演算法其實區域網有細就經常使用了,只是近年來公網速度提高,很容易找到RTT&<50ms的伺服器,因此根據上述演算法,在平均RTT=100ms(操作靈敏度1/10秒),情況下,保證自動計算關鍵幀適應各種網路條件後,就能夠像編寫單機遊戲一樣開發網遊,而不需狀態上作複雜的位置/狀態同步。

&" dw="1024" dh="720" class="origin_image zh-lightbox-thumb lazy" w="1024" data-original="https://pic1.zhimg.com/e5910ad11da4de79ce3bb950913ab1f9_r.jpg" data-actualsrc="//i1.wp.com/pic1.zhimg.com/50/e5910ad11da4de79ce3bb950913ab1f9_hd.jpg">

從上圖的演示中可以看到,兩個模擬器進程都在運行1941這個遊戲,兩邊客戶端使用了該演算法,將邏輯統一在一個整體中。

&" dw="828" dh="336" class="origin_image zh-lightbox-thumb lazy" w="828" data-original="https://pic3.zhimg.com/a6c284f1a3e9058b16d57f00cb32ada3_r.jpg" data-actualsrc="//i1.wp.com/pic3.zhimg.com/50/a6c284f1a3e9058b16d57f00cb32ada3_hd.jpg">

最後這張圖是運行KOF99的效果圖,兩邊完美同步,上圖是我開發的街機對戰效果,在公網環境下,只要不是小型寬頻用戶,一般電信或者聯通用戶都能有一個比較好的體驗。

樂觀幀鎖定

針對傳統幀鎖定演算法網速慢會卡到網速快的問題,實踐中線上動作遊戲通常用「定時不等待」的方式再每次Interval時鐘發生時固定將操作廣播給所有用戶,不依賴具體每個玩家是否有操作更新:

  1. 單個用戶當前鍵盤上下左右攻擊跳躍是否按下用一個32位整數描述,服務端描述一局遊戲中最多8玩家的鍵盤操作為:int player_keyboards[8];

  2. 服務端每秒鐘50次向所有客戶端發送更新消息(包含所有客戶端的操作和遞增的幀號): update=(FrameID,player_keyboards)

  3. 客戶端就像播放遊戲錄像一樣不停的播放這些包含每幀所有玩家操作的update消息。

  4. 客戶端如果沒有update數據了,就必須等待,直到有數據到來。

  5. 客戶端如果一下子收到很多連續的update,則快進播放。

  6. 客戶端只有按鍵按下或者放開,就會發送消息給服務端(而不是到每幀開始才採集鍵盤),消息只包含一個整數。服務端收到以後,改寫player_keyboards

-------------

雖然網速慢的玩家網路一卡,可能就被網速快的玩家給秒了(其他遊戲也差不多)。但是網速慢的玩家不會卡到快的玩家,只會感覺自己操作延遲而已。另一個側面來說,土豪的網宿一般比較快,我們要照顧。

指令緩存

針對高級別的抽象指令(非前後可以覆蓋的鍵盤操作),比如即時戰略遊戲中,各種高級操作指令,在「樂觀幀鎖定」中,客戶端任何操作都是可靠消息發送到服務端,服務端緩存在對應玩家的指令隊列裡面,然後定時向所有人廣播所有隊列裡面的歷史操作,廣播完成後清空隊列,等待新的指令上傳。客戶端收到後按順序執行這些指令,為了保證公平性,客戶端可以先執輪詢行每個用戶的第一條指令,執行完以後彈出隊列,再進入下一輪,直到沒有任何指令。這樣在即時戰略遊戲中,選擇 250ms一個同步幀,每秒四次,已經足夠了。如果做的好還可以象 AOE一樣根據網速調整,比如網速快的時候,進化為每秒10幀,網速慢時退化成每秒4幀,2幀之類的。

————–

隨機數需要服務端提前將種子發給各個客戶端,各個客戶端算邏輯時用該種子生成隨機數,另外該例子以鍵盤操作為例,實際可以以更高級的操作為例,比如「正走向A點」,「正在攻擊」等。幀鎖定系列方法目前也成功的被應用到了若干線上實時動作遊戲中。

PS:可以把整段戰鬥過程的操作和隨機數種子記錄下來,不但可以當錄像播放,還可以交給另外一台服務端延遲驗算,還可以交給其他空閑的客戶端驗算,將驗算結果的 hash值進行比較,如果相同則認可,如果不通則記錄或者處理,服務端如果根據遊戲當前進程加入一些臨時事件(比如天上掉下一個寶箱),可以在廣播的時候附帶。

----------------

關於幀鎖定系列的方法有很多類似實現(包括後面提到的幀間無等待改進,包括 Lock Step等),但是他們的核心都是一個:保證所有客戶端每幀的輸入都一樣。這樣的方式被格鬥遊戲,RTS和足球(FIFA類)、籃球(NBA)等體育和動作遊戲大量使用,比如我們熟悉的各大戰網平台遊戲(Xbox Live等),還有很多基於模擬器的街機對戰平台。以及不少大型多人橫版動作遊戲。以開發便利,同步邏輯直觀而受到大家歡迎。

幀鎖定演算法多用在 C/S模型中(或者一人做主多人做從的P2P里),它和 LockStep(多用於P2P)共同存在的問題就是 「網速慢的玩家會卡到網速快的玩家」,老式遊戲經常一個角色斷網,所有人就在那裡等待。為此出現了幀鎖定的改良版本 「樂觀幀鎖定」(具體描述見幀鎖定文章的下半部分)經過了不少遊戲的實踐檢驗。先前還有幾款上線的橫版格鬥頁游用 Flash 的 TCP without NODELAY 來跑該演算法(由於近兩年國內網速提高,Flash的 Tcp without NODELAY也能做很多事情了),效果還不錯。

具體實施時用不著按照文所述每一個步奏都相同,可以有很多變通。比如不一定是有變化的時候才通知服務端,有線上某橫版格鬥頁游就是也可以每秒 20次向服務端直接發送數據(flash時鐘不準需要自己獨立計時),服務端再每秒 40次更新回所有客戶端,看具體情況而定。

也有使用 UDP的端游,客戶端每秒鐘上傳50次鍵盤信息到服務端,丟了就丟了,後面持續發送過來的鍵盤數據會覆蓋前面的數據,所以丟了沒關係,更快捷。當然,UDP也不是必須的,近兩年網速提高很快,省內都能做到10ms的 RTT 了,跨省也就 50ms的rtt,不少頁游上用該方法上裸的 TCP 照樣跑的很順暢。

而近兩年動作遊戲領域也湧現出一些新的改良方法,比如 Time Warp,以客戶端先行+邏輯不一致時回滾的方式,帶來了更好的同步效果,俗稱時間回退法。不果國內暫時沒看到有遊戲這麼嘗試,更多的是國外近兩年的雙人動作遊戲比較多,要求遊戲每幀狀態都可以保存,邏輯上開發會複雜一些。國內大部分是超過兩人出去副本的,在3-4人出去 PK的情況下,引入狀態回退,會讓整個效果大打折扣。不果2人的效果確實有所改進,有興趣的同學可以搜索 Time Warp相關的論文。

----------------

&" dw="594" dh="292" class="origin_image zh-lightbox-thumb lazy" w="594" data-original="https://pic4.zhimg.com/f6ce46be7ec669add402587050527629_r.jpg" data-actualsrc="//i1.wp.com/pic4.zhimg.com/50/f6ce46be7ec669add402587050527629_hd.jpg">

2009年,雲遊戲(遊戲遠程渲染)技術得到廣泛應用,客戶端上傳操作,服務端遠程渲染,並以低延遲視頻編碼流的方式傳回給客戶端,用的就是這樣類似的技術。客戶端不需要高額的硬體,也不存在盜版問題,其中 Gaikai和 OnLive兩家公司做的比較好。

2012年,Sony推出 Playstation Now技術,可以在 PSV和 PS3/PS4上玩雲遊戲,玩家不需要購買遊戲就可以免費體驗一定時間。使得 PSV/PS3等低端硬體也可以流暢的跑 PS4遊戲。

但是目前國外網路環境下跑的還比較流暢,國內的網路環境要低延遲傳送 HD畫質的視頻流還比較困難,視頻都是比較費帶寬的。但是幀鎖定等保證每幀輸入一致的演算法,在當今的網路質量下傳遞一下玩家操作,還是沒有任何問題的。

更多閱讀:《再談網路遊戲同步》

----


題主,首先你的標題本身就有問題,因為: 延遲是無法避免的,只能被隱藏 。如果你加的網路延遲有那麼多,那麼你玩遊戲的延遲也會有那麼多,只會多,不會少。

截至到答題為止,我看了上面幾個高分的回答,似乎都沒有針對題主的問題做特別針對的回答。

比如說 @韋易笑 前輩提到的幾種同步手段,「幀同步」和「影子跟隨」,都算是一些比較通用和經典的手段。但題主說的是手機格鬥遊戲,這兩種方法都不太適合。

Lock-Step的固定延遲2幀,再加上互聯網本身的延遲,一般最終的延遲都會超過100ms了。在傳統的街機格鬥遊戲中,這100ms根本是不能接受的。

Snapshot interpolation 這種方法多用在第一人稱射擊和賽車類遊戲中。他採用的延遲補償方法比較適合這類遊戲。人們看不清也不會抱怨遠方那模糊的對手手裡的槍的槍口是不是真的準星精確地瞄準到了我的頭上。人們也看不清也不會抱怨不會在乎賽車急速並駕齊驅衝過終點線的時刻,到底是我的領先那麼幾公分還是你的。

但題主說的格鬥遊戲,我覺得不屬於這上面的兩者。

從題主的描述來看,題主顯然是在做這類型的遊戲。而我沒有做過,相比之下我不能太過裝逼,下面我說的解決方案只是我覺得可行的:

Understanding Fighting Game Networking

這種技術歸根結底就是一個字——rollback

不錯,就是你描述中擔心的

格鬥遊戲的行為也不像MMORPG這樣可以預測,或者強制拉回,總不能畫面上已經出現擊中受傷動畫,突然又切到了擊空與閃避的動畫。

我的建議就是你可以去看看他所描述的那些遊戲(視頻或者在線體驗),你這個擔心到底成立不成立,rollback的效果到底能不能接受。

還有,TCP真的該換了。


推薦閱讀:

Cocos Creator 會不會像Cocos Studio一樣半路被停掉?
遊戲中的戰鬥回放的實現原理和機制是什麼?包括即時戰鬥和離線戰鬥。
遊戲項目盈利後沒有給策劃分紅是業內常態嗎,這是否合理?
剛入職unity開發擔心完不成需求,怎麼辦?
分散式的環境下, MySQL和Redis如何保持數據的一致性?

TAG:手機遊戲開發 |