轉載:http://www.gameres.com/774540.htmlhtml
農藥自從上線以來,依靠着強大的產品力以及騰訊的運營能力,在遊戲市場上表現可謂是風生水起,根據第三方的調研數據顯示,《王者榮耀》滲透率達到22.3%,用戶規模達到2.01億人,每日的日活躍用戶(DAU)均值爲5412.8萬人。 如此可觀的數據,使人十分欽佩。
固然了,做爲技術人,更願意從技術上了解去一些王者榮耀的實現原理和架構方式,從中找到新的知識領域,擴展本身的知識邊界,豐富本身的專業技能。藉助這個遊戲,這一篇咱們來聊一聊王者榮耀的技術實現以及同步方式,更多的從MOBA(多人在線戰術競爭遊戲)方向來解析推理王者的實現方案,如如有分析的不盡的方向,歡迎一塊兒探討改進。如下是主要講解的幾個重點:
1.服務器架構
2.通訊方式
3.同步方案
4.技能同步
5.斷線重連
1、服務器架構
不難發現,王者榮耀的服務器採用房間模式,每一個玩家登錄之後,而後進入大廳,進行匹配遊戲。匹配完成以後,把一塊兒對戰的玩家放到一個房間內進行對戰。編程
房間類玩法和MMORPG有很大的不一樣,在於其在線廣播單元的不肯定性和廣播數量很小,並且須要匹配一臺房間服務器讓少數人進入一個服務器。
這一類遊戲最重要的是其「遊戲大廳」的承載量,每一個「遊戲房間」受邏輯所限,須要維持和廣播的玩家數據是有限的,可是「遊戲大廳」須要維持至關高的在線用戶數,因此通常來講,這種遊戲仍是須要作「分服」的。而「遊戲大廳」裏面最有挑戰性的任務,就是「自動匹配」玩家進入一個「遊戲房間」,這須要對全部在線玩家作搜索和過濾,以及爲了更好的體驗,會對玩家進行分地區進行匹配,以方便得到更快速的同步。
通常的方式是玩家先登陸「大廳服務器」,而後選擇組隊遊戲的功能,服務器會通知參與的全部遊戲客戶端,新開一條鏈接到房間服務器上(房間服務器與參與遊戲的十個玩家交互),這樣全部參與的用戶就能在房間服務器裏進行遊戲交互了。
2、通訊方式
說到通訊方式,通常會有http和socket 兩種方式,但http底層也是採用socket,只是每次通訊完成之後都會斷開,這種方式對於須要頻繁交互的雙方來講,顯得效率過低了,因此通常實時要求高的遊戲都是採用socket方式來通訊。(遊戲通常都採起socket通訊)
但是sokect通訊,又分爲兩種:TCP vs UDP,具體是採用那種socket類型,須要具體來看遊戲遊戲類型。如下是兩種類型的優劣:安全
從上面的對比中,咱們能夠會發現,關於socket,咱們想作的事情,tcp都幫咱們作了,咱們只須要創建連接,而後像讀寫文件同樣讀寫就能夠了。而udp須要咱們本身設計一切。看到這一切,你可能第一感受就是採用tcp而非udp,那麼真實狀況是如此麼?基於遊戲的業務以及場景不一樣,我能夠明確的告訴你,王者榮耀是採用udp的,包括騰訊多數長連接手遊都是採用udp(對其進行改造,用其餘的方式儘可能保證可靠,實際上TCP也不是徹底可靠的),這是爲什麼?
一、tcp保證數據可靠性是有代價的
tcp可以保證數據包的可靠性和有序,這一切都幫你封裝好了。TCP發送一個數據包,等待一段時間,直到檢測到數據包丟失了,若是沒有接收到它的ACK,接下來就從新發送丟失的數據包到目標計算機。重複的數據包將被丟棄在接收端,亂序的數據包將被從新排序。以此來保證數據包的可靠性和有序性。
但爲了保證可靠和有序,就要保證TCP不管什麼狀況,只要數據包出錯,就必須等待數據包的重發。這是什麼意思吶,就是說,即便最新的數據已經到達,但仍是不能訪問這些數據包,新到的數據會被放在一個隊列中,須要等待丟失的包從新發過來以後,全部數據沒有丟失才能夠訪問。
如此,若是遇到網絡環境太差或者不穩定,好比說國內的移動網絡,或者是遭遇到了網絡阻塞,出現一個數據包丟失,全部事情都須要停下來等待這個數據包重發。客戶端會出現等待接收數據,玩家操做會出現卡頓以及響應不及時的現象。
二、udp的可靠性—DIY手動組裝
從上面咱們能夠知道udp主要在可靠性上主要是不能保證數據包的順序,好比第100個收到的數據包並不必定是第100個發出的數據包,同時也沒法保證不丟包,期間有一個包丟失,udp本是也不會去校檢。若是這兩個問題解決了,udp的大部分可靠性問題也就解決了。
具體的方案咱們這一篇就不在細說,大致上是如此來解決:
一、爲每一個數據包增長序列號,每發一次包,增長本地序號。
二、每一個數據包增長一段位域,用來容納多個確認符。確認字符多少個,跟進應用的發包速率來以爲,速率越高,確認字符的數量也相應越多。
三、每次收到包,把收到的包上序列號變爲確認字符,發送包的時候帶上這些確認字符。
四、若是從確認字符裏面發現某個數據包有丟失,把它留給應用程序來編寫一個包含丟失數據的新的數據包,必要的話,這個包還會用一個新的序列號發送。
五、針對屢次收到同一包的時候能夠放棄它
3、同步方案
遊戲中常見的同步方案,有狀態同步和幀同步,通常大型的MMOARPG都是採用的是狀態同步,好比魔獸世界,狀態同步採用C/S架構,全部的狀態由服務器來控制,安全性比較高,可是流量比較大。幀同步採用的是囚徒模式,全部c端強制採用一個邏輯幀率,從而保證輸出一致,其特色是流量小,安全性比較差。
王者榮耀採用的就是幀同步,那麼具體幀同步是什麼,如何實現的,咱們從兩個地方來分解:
一、幀率
什麼是幀率,可能沒有作過client同窗並非很清楚這個術語,咱們從一個小例子來說解一下。我記得小時候有一種小人書,快速翻看就能夠看到漫畫上的人物會動起來。
因爲人類眼睛的特殊生理結構,若是所看畫面之幀率高於每秒約10-12幀的時候,就會認爲是連貫的, 此現象稱之爲視覺暫留。這也就是爲何電影膠片是一格一格拍攝出來,而後快速播放的,就像上圖快速翻小人書同樣。
遊戲中的全部動畫也是採用這種方式來渲染,只不過幀率是有GPU來控制,你所看到的畫面都是有都是有GPU一幀幀渲染的,好比30幀/s,你所看到的畫面就比較流暢了。而幀率越高你所看到的越流暢。
二、Lockstep—幀同步
幀同步能夠說是經過幀率延伸過來的,你能夠把一個遊戲當作一個巨大的狀態機,全部的參與者都採用同一個邏輯幀率來不斷的向前推動。
咱們看以下2個圖:服務器
圖中是A、B、C三個玩家的時間軸,這個時間軸不是電腦上的本地時間,而是A、B、C聯機時定義的一個時間軸。虛線分隔出來時間片稱爲turn,能夠理解成一幀。箭頭表示該玩家將本身的操做指令廣播給其餘玩家。
咱們把一盤遊戲當作一個大型的狀態機,由於你們玩的是同一款的遊戲,所以F是相同的,初始狀態S0也是相同的。在第一個turn結束時,全部玩家都接收到了徹底同樣的輸入I,注意這裏的I不是一個值,而是包含了當前遊戲中全部玩家的操做指令集合。t1時刻全部玩家的電腦自行計算結果。因爲F、S0和I是固定的,因此每一個玩家電腦上計算出的下一個狀態S1必定是相同的。
因此經過上面咱們能夠知道:
一、咱們把遊戲的前進分爲一幀幀,這裏的幀和遊戲的渲染幀率並非一個,只是借鑑了幀的概念,自定義的幀,咱們稱爲turn。遊戲的過程就是每個turn不斷向前推動,每個玩家的turn推動速度一致。
二、每一幀只有當服務器集齊了全部玩家的操做指令,也就是輸入肯定了以後,才能夠進行計算,進入下一個turn,不然就要等待最慢的玩家。以後再廣播給全部的玩家。如此才能保證幀一致。
三、Lockstep的遊戲是嚴格按照turn向前推動的,若是有人延遲比較高,其餘玩家必須等待該玩家跟上以後再繼續計算,不存在某個玩家領先或落後其餘玩家若干個turn的狀況。使用Lockstep同步機制的遊戲中,每一個玩家的延遲都等於延遲最高的那我的。
四、因爲你們的turn一致,以及輸入固定,因此每一步全部客戶端的計算結果都一致的。
咱們來看看具體的執行流程:網絡
上圖中咱們能夠明顯看到,這種囚徒模式的幀同步,在第二幀的時候,由於玩家1有延遲,而致使第二幀的同步時間發生延遲,從而致使全部玩家都在等待,出現卡頓現象。
4、樂觀鎖&斷線重連
囚徒模式的幀同步,有一個致命的缺陷就是,若聯網的玩家有一個網速慢了,勢必會影響其餘玩家的體驗,由於服務器要等待全部輸入達到以後再同步到全部的c端。另外若是中途有人掉線了,遊戲就會沒法繼續或者掉線玩家沒法重連,由於在嚴格的幀同步的狀況下,中途加入遊戲是從技術上來說是很是困難的。由於你從新進來以後,你的初始狀態和你們不一致,並且你的狀態信息都是丟失狀態的,好比,你的等級,隨機種子,角色的屬性信息等。 好比玩過早期的冰封王座都知道,一旦掉線基本這局就廢了,須要重開,至於爲什麼沒有卡頓的現象,由於那時都是解決方案都是採用局域網的方式,因此基本是沒有延遲問題的。
後期爲了解決這個問題,現在包括王者榮耀,服務器會保存玩家當場遊戲的遊戲指令以及狀態信息,在玩家斷線重連的時候,可以恢復到斷線前的狀態。不過這個仍是沒法解決幀同步的問題,由於嚴格的幀同步,是要等到全部玩家都輸入以後,再去通知廣播client更新,若是A服務器一直沒有輸入同步過來,你們是要等着的,那麼如何解決這個問題?
採用「定時不等待」的樂觀方式在每次Interval時鐘發生時固定將操做廣播給全部用戶,不依賴具體每一個玩家是否有操做更新。如此幀率的時鐘在由服務器控制,當客戶端有操做的時候及時的發送服務器,而後服務端每秒鐘20-50次向全部客戶端發送更新消息。以下圖:架構
上圖中,咱們看到服務器不會再等到蒐集完全部用戶輸入再進行下一幀,而是按照固定頻率來同步玩家的輸入信息到每個c端,若是有玩家網絡延遲,服務器的幀步進是不會等待的,好比上圖中,在第二幀的時候,玩家A的網速慢,那麼他這個時候,會被網速快的玩家給秒了(其餘遊戲也差很少)。可是網速慢的玩家不會卡到快的玩家,只會感受本身操做延遲而已。
5、技能同步
遊戲中有不少是和機率相關的,好比說技能的傷害有必定機率的暴擊傷害或者折光被擊等。按照幀同步的話,基於相同的輸入,每一個玩家的client都是獨立計算傷害的,那麼如何保證全部電腦的暴擊傷害一致那。這個時候就須要用到僞隨機了。
大部分編程語言內置庫裏的隨機數都是利用線性同餘發生器產生的,若是不指定隨機種子(Random Seed),默認以當前系統時間戳做爲隨機種子。一旦指定了隨機種子,那麼產生的隨機數序列就是肯定的。就是說兩臺電腦採用相同的隨機種子,第N次隨機的結果是一致的。
因此在遊戲開始前,服務器爲每一個玩家分配一個隨機種子,而後同步給client,如此每一個client在計算每一個角色的技能時候,就能保證傷害是一致的。這也是多數幀同步遊戲採用的方案,包括王者榮耀。dom