從王者榮耀聊聊遊戲的幀同步

2022-06-18 09:30:14 字數 3996 閱讀 3233

如此可觀的資料,令人十分欽佩。

伺服器架構

通訊方式

同步方案

技能同步

斷線重連

不難發現,王者榮耀的伺服器採用房間模式,每個玩家登陸以後,然後進入大廳,進行匹配遊戲。匹配完成之後,把一起對戰的玩家放到乙個房間內進行對戰。

一般的方式是玩家先登入「大廳伺服器」,然後選擇組隊遊戲的功能,伺服器會通知參與的所有遊戲客戶端,新開一條連線到房間伺服器上,這樣所有參與的使用者就能在房間伺服器裡進行遊戲互動了。

說到通訊方式,一般會有http和socket 兩種方式,但http底層也是採用socket,只是每次通訊完成以後都會斷開,這種方式對於需要頻繁互動的雙方來說,顯得效率太低了,所以一般實時要求高的遊戲都是採用socket方式來通訊。

可是sokect通訊,又分為兩種:tcp vs udp,具體是採用那種socket型別,需要具體來看遊戲遊戲型別。以下是兩種型別的優劣:

tcp能夠保證資料報的可靠性和有序,這一切都幫你封裝好了。tcp傳送乙個資料報,等待一段時間,直到檢測到資料報丟失了,如果沒有接收到它的ack,接下來就重新傳送丟失的資料報到目標計算機。重複的資料報將被丟棄在接收端,亂序的資料報將被重新排序。以此來保證資料報的可靠性和有序性。

但為了保證可靠和有序,就要保證tcp無論什麼情況,只要資料報出錯,就必須等待資料報的重發。這是什麼意思吶,就是說,即使最新的資料已經到達,但還是不能訪問這些資料報,新到的資料會被放在乙個佇列中,需要等待丟失的包重新發過來之後,所有資料沒有丟失才可以訪問。

如此,如果遇到網路環境太差或者不穩定,比如說國內的流動網路,或者是遭遇到了網路阻塞,出現乙個資料報丟失,所有事情都需要停下來等待這個資料報重發。客戶端會出現等待接收資料,玩家操作會出現卡頓以及響應不及時的現象。

從上面我們可以知道udp主要在可靠性上主要是不能保證資料報的順序,比如第100個收到的資料報並不一定是第100個發出的資料報,同時也無法保證不丟包,期間有乙個包丟失,udp本是也不會去校檢。如果這兩個問題解決了,udp的大部分可靠性問題也就解決了。

具體的方案我們這一篇就不在細說,大體上是如此來解決:

1、為每個資料報增加序列號,每發一次包,增加本地序號。

2、每個資料報增加一段位域,用來容納多個確認符。確認字元多少個,跟進應用的發包速率來覺得,速率越高,確認字元的數量也相應越多。

3、每次收到包,把收到的包上序列號變為確認字元,傳送包的時候帶上這些確認字元。

4、如果從確認字元裡面發現某個資料報有丟失,把它留給應用程式來編寫乙個包含丟失資料的新的資料報,必要的話,這個包還會用乙個新的序列號傳送。

5、針對多次收到同一包的時候可以放棄它

遊戲中常見的同步方案,有狀態同步和幀同步,一般大型的mmoarpg都是採用的是狀態同步,比如魔獸世界,狀態同步採用c/s架構,所有的狀態由伺服器來控制,安全性比較高,但是流量比較大。幀同步採用的是囚徒模式,所有c端強制採用乙個邏輯幀率,從而保證輸出一致,其特點是流量小,安全性比較差。

王者榮耀採用的就是幀同步,那麼具體幀同步是什麼,如何實現的,我們從兩個地方來分解:

什麼是幀率,可能沒有做過client同學並不是很清楚這個術語,我們從乙個小李子來講解一下。我記得小時候有一種小人書,快速翻看就可以看到漫畫上的人物會動起來。如下面這種:

超過1m上傳不刪了,我也無奈

遊戲中的所有動畫也是採用這種方式來渲染,只不過幀率是有gpu來控制,你所看到的畫面都是有都是有gpu一幀幀渲染的,比如30幀/s,你所看到的畫面就比較流暢了。而幀率越高你所看到的越流暢。

幀同步可以說是通過幀率延伸過來的,你可以把乙個遊戲看成乙個巨大的狀態機,所有的參與者都採用同乙個邏輯幀率來不斷的向前推進。

我們看如下2個圖:

圖中是a、b、c三個玩家的時間軸,這個時間軸不是電腦上的本地時間,而是a、b、c聯機時定義的乙個時間軸。虛線分隔出來時間片稱為turn,可以理解成一幀。箭頭表示該玩家將自己的操作指令廣播給其他玩家。

我們把一盤遊戲看成乙個大型的狀態機,因為大家玩的是同一款的遊戲,因此f是相同的,初始狀態s0也是相同的。在第乙個turn結束時,所有玩家都接收到了完全一樣的輸入i,注意這裡的i不是乙個值,而是包含了當前遊戲中所有玩家的操作指令集合。t1時刻所有玩家的電腦自行計算結果。由於f、s0和i是固定的,所以每個玩家電腦上計算出的下乙個狀態s1一定是相同的。

所以通過上面我們可以知道:

1、我們把遊戲的前進分為一幀幀,這裡的幀和遊戲的渲染幀率並不是乙個,只是借鑑了幀的概念,自定義的幀,我們稱為turn。遊戲的過程就是每乙個turn不斷向前推進,每乙個玩家的turn推進速度一致。

2、每一幀只有當伺服器集齊了所有玩家的操作指令,也就是輸入確定了之後,才可以進行計算,進入下乙個turn,否則就要等待最慢的玩家。之後再廣播給所有的玩家。如此才能保證幀一致。

3、lockstep的遊戲是嚴格按照turn向前推進的,如果有人延遲比較高,其他玩家必須等待該玩家跟上之後再繼續計算,不存在某個玩家領先或落後其他玩家若干個turn的情況。使用lockstep同步機制的遊戲中,每個玩家的延遲都等於延遲最高的那個人。

4、由於大家的turn一致,以及輸入固定,所以每一步所有客戶端的計算結果都一致的。

我們來看看具體的執行流程:

上圖中我們可以明顯看到,這種囚徒模式的幀同步,在第二幀的時候,因為玩家1有延遲,而導致第二幀的同步時間發生延遲,從而導致所有玩家都在等待,出現卡頓現象。

囚徒模式的幀同步,有乙個致命的缺陷就是,若聯網的玩家有乙個網速慢了,勢必會影響其他玩家的體驗,因為伺服器要等待所有輸入達到之後再同步到所有的c端。另外如果中途有人掉線了,遊戲就會無法繼續或者掉線玩家無法重連,因為在嚴格的幀同步的情況下,中途加入遊戲是從技術上來講是非常困難的。因為你重新進來之後,你的初始狀態和大家不一致,而且你的狀態資訊都是丟失狀態的,比如,你的等級,隨機種子,角色的屬性資訊等。 比如玩過早期的冰封王座都知道,一旦掉線基本這局就廢了,需要重開,至於為何沒有卡頓的現象,因為那時都是解決方案都是採用區域網的方式,所以基本是沒有延遲問題的。

後期為了解決這個問題,如今包括王者榮耀,伺服器會儲存玩家當場遊戲的遊戲指令以及狀態資訊,在玩家斷線重連的時候,能夠恢復到斷線前的狀態。不過這個還是無法解決幀同步的問題,因為嚴格的幀同步,是要等到所有玩家都輸入之後,再去通知廣播client更新,如果a伺服器一直沒有輸入同步過來,大家是要等著的,那麼如何解決這個問題?

採用「定時不等待」的樂觀方式在每次interval時鐘發生時固定將操作廣播給所有使用者,不依賴具體每個玩家是否有操作更新。如此幀率的時鐘在由伺服器控制,當客戶端有操作的時候及時的傳送伺服器,然後服務端每秒鐘20-50次向所有客戶端傳送更新訊息。如下圖:

上圖中,我們看到伺服器不會再等到蒐集完所有使用者輸入再進行下一幀,而是按照固定頻率來同步玩家的輸入資訊到每乙個c端,如果有玩家網路延遲,伺服器的幀步進是不會等待的,比如上圖中,在第二幀的時候,玩家a的網速慢,那麼他這個時候,會被網速快的玩家給秒了(其他遊戲也差不多)。但是網速慢的玩家不會卡到快的玩家,只會感覺自己操作延遲而已。

遊戲中有很多是和概率相關的,比如說技能的傷害有一定概率的暴擊傷害或者折光被擊等。按照幀同步的話,基於相同的輸入,每個玩家的client都是獨立計算傷害的,那麼如何保證所有電腦的暴擊傷害一致那。這個時候就需要用到偽隨機了。

大部分程式語言內建庫里的隨機數都是利用線性同餘發生器產生的,如果不指定隨機種子(random seed),預設以當前系統時間戳作為隨機種子。一旦指定了隨機種子,那麼產生的隨機數序列就是確定的。就是說兩台電腦採用相同的隨機種子,第n次隨機的結果是一致的。

所以在遊戲開始前,伺服器為每個玩家分配乙個隨機種子,然後同步給client,如此每個client在計算每個角色的技能時候,就能保證傷害是一致的。這也是多數幀同步遊戲採用的方案,包括王者榮耀。

從《王者榮耀》談遊戲的幀同步

不難發現,王者榮耀的伺服器採用房間模式,每個玩家登陸以後,然後進入大廳,進行匹配遊戲。匹配完成之後,把一起對戰的玩家放到乙個房間內進行對戰。說到通訊方式,一般會有http和socket 兩種方式,但http底層也是採用socket,只是每次通訊完成以後都會斷開,這種方式對於需要頻繁互動的雙方來說,顯...

從王者榮耀看國產遊戲國際化

經過幾年的與歷史人物不符 兒童沉迷遊戲無法自拔等熱門話題的洗禮,王者榮耀的做法就是 順勢而為。荊軻不能是女的,容易誤導小孩子,好,那就改成阿珂。之後的新英雄也盡量不用歷史人物,頂多用個神話人物。估計以後國產遊戲是出不了類似日本那種把歷史人物娘化的了,總有家長會挑刺兒啊。孩子是有幾歲 歷史學得多麼不好...

從 王者榮耀 ,看 產品 運營 的博弈

在遊戲中,你可以通過出裝給出不同的玩法 在人生中,你需要用計畫讓自己活得更瀟灑。可是,偏偏我大學所在的這個班級的男生幾乎都是遊戲 動漫愛好者。自打一入學就被他們掛在嘴邊的 a站 b站 擼啊擼 這些我都聽不懂的名詞所籠罩,甚至一度沒有共同語言。近期,王者榮耀 這款遊戲更是空前火爆,無論是萌妹子 大叔還...