腾讯邓君:《王者荣耀》翻过的同步技术相关的三座大山
在Unity舉辦的Unite 2017上海開發者大會中,案例分享專場受到了業內的高度關注,眾多行業領軍人物針對過往的成功案例慷慨的分享了開發過程中的經驗教訓,而《王者榮耀》項目組技術總監鄧君的分享則無疑成為了焦點中的焦點。
雖然《王者榮耀》如今已經成為席卷一切的國民級游戲,但其在問世之初卻經歷過一段鮮為人知的調優期,而當時騰訊對于這款產品的重視程度和期待值也遠不及旗下的其他MOBA產品。
這款作品為何最終能成為MOBA手游標桿式的存在?其開發過程中究竟經歷了哪些困難和挑戰呢。鄧君在他的分享中給出了答案。
以下為星游社整理的演講精華:
這次的主題主要是講一下王者榮耀從立項之初經歷的慘淡時期到華麗的翻盤,這里不管碰到技術方面的問題,還是游戲方向上的改變,我是技術出身的,整個課題也是技術面的,會重點介紹王者榮耀和現在見到大部分不同的技術方案,它實際原理、問題和優化的思路。
先簡單自我介紹一下,我是2004年加入騰訊,在騰訊做了4年多的應用層面開發,還包括web各種各樣后臺都做過,經歷比較豐富,在2009年我回成都,剛好成都的崗位也就只有游戲部門是比較合適的,就轉行做游戲了。在成都這邊,參與過一個《QQ封神記》的開發,從封神記出來之后,又開發了一款游戲,這款游戲開發了三年多,游戲從1.0、2.0、3.0,這個時候再轉型做手游,直接做的王者榮耀。
我們介紹一下王者榮耀,現在了解王者榮耀或者在玩王者榮耀的人確實比較多,但是我們曾經也沒有想過王者榮耀有這樣的結果。當時端游很久都沒有做出來成績,業績和收入都面臨比較大的問題。霸三國做到1.0之后,要操作多個單位,2012、2011年的時候,大家覺得特別費操作,要控制很多單位的游戲,操作起來很難,一開始可以操作5支單位然后變成3支持,3支完了覺得也很痛苦,這個游戲策略性很強,慢慢把5個單位的技能合在一個身上。你要做創新,你要脫穎而出,是很難的事情。
在2014年年底的時候,2015年我們準備開一個手游團隊。為什么開手游團隊?國內環境里面,基本上都在開發手游,能夠繼續開發端游或者要準備立項端游的非常少,包括騰訊也就是2、3款端游在開發,端游還是有希望的,開發的團隊比較少,手游也是一個機會,希望在2015年把我們的霸三國端游在手游上呈現。這個時候我們進行了一個初期Demo的驗證,Demo驗證只有三個人,引擎的、框架的、后臺的,大概做了兩周到三周,把Demo做出來,里面有基本的進游戲、選人,然后可以釋放技能,正常的戰斗,到結算。但是是用Unity來做的,兩、三周做完之后,覺得Unity很好用,開發確實比較高,簡單的先這樣,2015年才開始進行一個真正的獨立招聘20、30人做手游項目,當時是這樣的想法。2014年年底的時候,我們制作人去公司開會,當時這是一個非常明智的決策,我們需要馬上暫停端游的開發,直接做手游。就是這樣的一次決策,真正的是扭轉了我們整個團隊的命運。如果晚一年,可能今天的游戲就是另外一個,應該不是王者。
為什么選擇Unity引擎
我們從端游轉型做手游,做手游肯定要面臨選擇什么樣的引擎,采用什么樣的方案進行手游的開發。當時的環境,周邊包括騰訊還有成都的創業團隊,基本上都是Unity,我都不知道,大概在2013、2014年出來很多游戲都是Unity,我們做Demo的時候,也會選擇大家用的,已經有產品進行驗證了,同時我們也考察它適不適合我們的團隊。Unity我們當時做Demo的理解,它確實對中小團隊,包括作為一些大型項目,它有幾個比較明顯的優勢。
1、 在兩三周你就可以做出Demo,易上手是一個非常大的優勢,在座可能都理解。
2、 另外,它的工具都是很完善的,能夠做到一站式解決,你不需要在這里面下載工具,那里面額外補充一些插件。
3、 另外還有它插件資源很豐富,我們從最開始做Demo的時候,基本上都是找一些我們可以用來驗證我們想法的,它肯定可以加快我們開發的效率。
4、 上面這三點加起來,是它非常明顯的優勢,開發效率特別高。
5、 還有跨平臺,那是肯定的,它本是就是跨平臺的引擎。
6、 還有你能夠對人員的補充,非常容易,因為在周邊包括社會上招聘都很容易招聘到熟悉Unity的開發人員。
我們這邊直接對比以前自己做引擎,或者用過其他的引擎,從效率上來講,我們選擇了一個開發效率最高的引擎。這里面回過頭來,從端游轉換到手游是在2014年底,我們真正開始的時候在2015年3月份就進行開發,這個時候我們開發的周期短,我們需要盡快把手游做上線。我們本身霸三國開發大概有40、50個人,后面把周邊的兄弟部門都合并在一起了,里面有一些會Unity、會手游的,還有一部分沒有手游開發經驗的,組合在一起,形成了100多人的團隊,進行了游戲的開發。
還有一個很重要的選擇,我們本身是一個網絡游戲。當時在2013、2014年的時候,游戲在pvp上面比較弱,大部分是卡牌游戲、單機游戲,我們本身是一個端游,它的生命力包括趣味性也是很足的,我們做手游的目標,即使我們里面有PVE的闖關內容,但是我們里面有最核心的東西還是PVP,讓玩家有真正的對抗,玩家與玩家有交流,體會到游戲的樂趣。
同步機制的抉擇
既然選擇了pvp,它可能就是一個網絡游戲,網絡游戲我們選擇用什么樣的同步機制呢?最常見的應該是cs狀態同步,我們端游也是這樣做的。后面我們為什么會選擇幀同步,后面再說。
先看一下狀態同步的優缺點。
1、 它的安全性非常高,基本上外掛沒有什么能力從中收益,基本上都是服務器校驗。
2、 另外狀態同步對于網絡的帶寬和抖動包有一個更強的適應能力,你有一個輸入延遲200、300后面又好了,你其實感受不出來它不太舒服的地方
3、 在開發游戲過程中,它的斷線重回比較快。如果我的游戲崩潰了,回來之后需要服務器把所有重要對象的狀態再同步一次過來,重新再創建出來就可以了。
4、 它的客戶端性能優化也比較明顯。客戶端在做性能優化的時候,它可以做裁剪,我看不到的角色我可以不用創建,也可以不用對它進行運算。
說完了優點,再說一下我認為的缺點。
1、 一個就是開發效率要相對幀同步差一些,很多時候你要從服務器客戶端的每一個角色對象的狀態之間保持一致,你很難做到它是一致的,包括客戶端和服務器端更新的頻率,他們對優化的一些裁剪,包括網絡的一些抖動,你要讓每一個狀態在客戶端有一個同步,是比較難,你要想調試這些東西,出現的漏洞、不一致的現象,調試周期比較長,想要達到優化好的水平,也是比較難的。
2、 它比較難做出動作類游戲打擊感和精確性。比如說你要做一個人是射擊類,他的×××每秒鐘要產生幾十顆,基于狀態同步是比較難的事情,因為在很短時間會產生很多角色,要通過創建、銷毀包括位置和運算。
3、 它的流量會隨著游戲的復雜度,角色的多少而增長。你做手游,也是想追求你在3G、4G也能夠玩pvp,對你付費流量的消耗,我們希望能夠做到一個比較好的水平,不希望能夠打一局游戲需要消耗幾十兆的數據流量。
我們再看一下幀同步,大部分人應該還是了解的。最初大家玩的心計、魔獸3都是幀同步,他們是基于局域網,網絡非常好,也不需要服務器,他們直接用新型的網絡就能夠搞定。幀同步的優點有幾個:
1、 開發效率比較高,為什么說開發效率比較高?如果你整體的框架是驗證通過,你把它的缺點解決了的話,你完全開發思路就跟寫單機一樣,你只需要遵從這樣的思路,盡量保證性能,該怎么寫就怎么寫,相對于我們經驗來說,以前要在狀態同步下面做一個復雜的技能,有很多段位的技能,也許可能要開發好幾天,才能有一個稍微過得去的結果,可能在幀同步下面,英雄做多段位技能很可能一天就搞定了。
2、 它的打擊感確實比較強,打擊感強除了我們說的各種反饋、特效、音效,還有它的準確性。你游戲里面看到這些揮舞的動作,它能夠在比較準確的時刻就能夠有反饋,包括它的密度可以做到很高的頻率,是狀態同步比較難做的。
3、 它的流量消耗是穩定的。大家應該看過星際的錄像,它的錄像只有幾百K,這里面就是網絡流量里面全是驅動游戲的輸入序列。幀同步只會隨著玩家數量,流量才會增長,如果玩家固定的話,流量不管你的游戲有多復雜,你的角色有多少,它基本上都是穩定的。這點延伸的好處是可以做觀戰,錄像的存儲、回放,包括基于錄像文件后續的處理都比較容易做。
說了這么多優點,它肯定也有缺點。
1、 最致命的是網絡要求比較高,如果你的網絡稍微有抖動,它是一個鎖幀的,如果有這樣的抖動,一段時間調用次數是不穩定的,網絡命令的延遲會有擠壓和舒展。
2、 它的反外掛能力很弱,幀同步邏輯都在客戶端里面,你可以查得到它有沒有作弊。游戲的邏輯是在客戶端,你可以修改它。為什么王者敢用這樣一個東西,當時選型的時候,半年的開發周期需要做出來,要做上線,要有幾十個英雄,有時間的壓力。另外一個這樣一個游戲類型,不像成長類的游戲,它是基于單局的,單局你修改這個東西,頂多影響這一局的勝負,不會存檔,你刷多少錢穿比較好的裝備,這本身是一個弱成長的游戲,我們認為它不是一個致命的缺點。你在這上面可以做到收益不明顯,你做完之后我們可以發現你有沒有作弊,作弊了一樣有懲罰。反外掛雖然缺點在,在王者這樣游戲類型下面不是特別明顯。
3、 斷線重回時間很長,我估計下面有非常多的玩家,也碰到過如果你玩著玩著最后閃退你回來有多痛苦,第二個100%等到完成你游戲進去了,游戲也結束了,這個幀同比是比較致命的,每一幀的鹽酸最后才能算到正確的狀態。
4、 它的邏輯性能優化有很大的壓力。大家應該沒有見到哪一款大型游戲用幀同步來做的,每一個邏輯對象都是需要在客戶端進行運算。如果你做一個主城,主城里面有上千人,上千人角色雖然看不到它,但是你需要對它進行有效的邏輯運算,這就是它無法做非常多的游戲對象需要更新的游戲場景。
為什么我們選擇了幀同步而放棄了狀態同步呢?前面提到它兩個優點缺點是相對的,這邊的優點對于那邊來說就是缺點。對于我們手游立項的時候,最重要就是時間。當時市面上正在開發的包括騰訊內部的都不止王者一款在開發,大家都在爭取上線的時間,我們可能會選擇一個開發時間周期最短的方案。然后我們做端游也有一個深刻的體會,做有趣的英雄,有趣的技能,它在狀態同步上面很難調出一個比較滿意的效果。它的優點包括我們自己對于狀態同步的體會上面,最后我們依然選擇幀同步的方案。選擇幀同步方案,確實現在回過頭來講,我們把缺點優化掉規避掉,它帶來的好處是比較明顯的。我們的游戲比較好玩,除了英雄的設計包括整個技能的感覺,還有很重要的一點,它確實在做一些非常有特色的英雄,它的技能、反饋、體驗上面都是做的不錯,這是基于幀同步技術方案的優勢。
開發過程中面臨的三座大山
我們選擇了方案之后,當時覺得很high,覺得這樣一個技術方案開發起來得心應手,效率如此之高,做出來的效果也很好。但是它也有好的一面,也有壞的一面,技術測試版本上線后質量不好,其中技術層面應該就是這上面的三座大山。
第一個同步性,同步性這塊容易解決,其實也解決了。
第二個也是最大的一個問題是網絡問題,幀同步它的網絡問題導致我們對它技術方案的原理沒有吃透,碰到了一些問題,那時候游戲感覺延遲很重,畫面卡頓,你明顯感覺走路抖動的現象。
第三個是性能問題,這個問題始終存在,也一直在優化。
先看一下第一座大山,最容易解決的,說一下幀同步的技術原理,相當簡單,10、20年前就有了,它要一個相同初始的狀態,后面你需要有一個相同的輸入,我往下一幀執行,執行的時候我所有代碼的流程,大家走的是一樣的,有了相同輸入之后,輸入包括第一幀、第二幀、第三幀,有了輸入然后要執行相同流程,大家走的一模一樣,這個結果調用完了以后,又有一個新狀態,下一個狀態大家又有一樣,完成了循環,相同的狀態,相同的流程,不停的這樣循環下去。這個原理雖然簡單,但是你要去實現它的時候,還是會有很多坑。
右邊寫的是實現要點,這是我們在解決第一座大山經驗的總結,也是我們實際開發過程當中做的事情。
1、 我們所有的運算都是基于整數,沒有浮點數。浮點數是用分子分母表達的。
2、 我們可能還會用到第三方的組件,幀組件也要需要進行一個比較嚴格的甄別。我們本身用的公司里面關于時間軸的編輯器里面,最初也是是浮點數,我們都是進行重寫改造的。
3、 你初次接觸幀同步里面出問題,就是寫邏輯的時候和本地相關、和“我”相關,這樣就導致走到不同分支,真正客戶端跟邏輯的話,要跟我這樣一個概念無關。
4、 還有隨機數,這個要嚴格一致。這是實現的要點,嚴格按照這上面的規則寫代碼還是有可能不同步,本身就很難杜絕這樣的問題。
5、 真正一個比較重要的是開發者要提升發現不同步的能力,什么時候不同步了,不同步你還要知道不同步在什么點,這是最關鍵的。你需要通過你的經驗和總結提升這樣的能力。這個能力還是通過輸出來看不同客戶端不同輸出,找到發生在什么點。特別是在概率比較低。
比如在《王者榮耀》中,我們看到不同步的現象應該是這樣,有人對著墻跑,你看到就是你和別人玩的游戲是不一樣的,進入平行世界。
最開始測試的時候,我們希望不同步率達到1%,就是100局里面有1局出現不同步,我們就算游戲合格,其實對于這么大一個體量游戲來說是有問題的,經過我們不停的努力,現在是在萬分之幾。一萬局游戲里面,可能有幾局是不同步的。這個問題不一定是代碼原因或者沒有遵循這些要點寫出來的,包括你去修改內存,包括你去加載資源的時候,本地資源有損害或者缺失,或者是異常。異常說白了,你沒有辦法往下執行,大家走了不同分支,這都可能引起最終是不同步的。如果你不同步概率比較低,這種萬分之幾概率的時候,很難通過測試來去還原,去找到這樣不同步的點。
最開始我們游戲出現不同步的時候,就是周末玩家開黑多的時候,隨著你的概率越來越低,基本上你就自己還原不出來了,只能依靠玩家幫你還原這樣的場景,來分析這樣的不同步。
同步性遵循這樣的要點,按照這樣的思路來寫,加上你不同步定位的能力,有了監控手段能夠去發現,這個問題其實就解決了。解決之后,你就可以好好享受幀同步的開發優勢。
第二座大山就是網絡,技術測試版本出臺的時候,延遲非常大,而且還是卡頓,現在看一下幀同步里面比較特別的地方。幀同步有點像在看電影,它傳統的幀同步需要有buffer,每個玩家輸入會轉發給所有客戶端,互相會有編號,第幾幀,第幾幀的輸入,假如說我現在收到第N幀,如果我收到第N+1幀的話,N幀這一幀我是可以執行的,是這樣一個情況。服務器會按照一定的頻率,不同的給大家同步幀編號,包括這一幀的輸入帶給客戶端,如果帶一幀給你的數據你拿到之后就執行,下一幀數據沒來就不能執行,它的結果有可能你網絡非常穩定,絕對理想值的情況下還好,現實網絡不是這樣的。幀同步要解決問題就是有buffer,以前有動態的buffer,它有1到n這樣的緩沖區,根據網絡抖動的情況,收入然后放到隊列里面。這個buffer的大小,會影響到這兩個東西,一個就是延遲還有卡頓。如果你的buffer越小,你的延遲就越低,你拿到以后你不需要緩沖等待,馬上就可以執行。但是如果下一幀沒來,buffer很小,你就不能執行,最終導致的結果你的延遲還好,但是卡頓很明顯。你會調到幀同步的buffer,假如我們認為網絡延遲是1秒,你抖動調到1秒,那得到的結果雖然你畫面不抖動了,但是你的延遲極其高。最壞的網絡情況都考慮進去,buffer足夠大,跟看視頻是一樣的,平行的東西,看你調大條小。一些局部的措施我們都做過,都是一樣的問題。
我們怎么優化卡頓這方面呢?本身剛才也提到了,它應該幀同步有buffer,這個buffer可以是1也可以到n,我們要解決我們的延遲問題,我們就讓buffer足夠小,最后我們做到buffer是零,它不需要buffer,服務器給了我n,馬上知道是n,我收到n,我知道下一次肯定是n+1,所以我收到n之后馬上就把n這一幀的輸入執行了,下一步可能就涉及到了為什么不卡頓了,畫面不抖動了,是最后一條,是本地插值平滑加邏輯與表現分離。客戶端只負責一些模型、動畫、它的位置,它會根據綁定的邏輯對象狀態、速度、方向來進行一個插值,這樣可以做到我們的邏輯幀率和渲染幀率不一樣,但是做了插值平滑和邏輯表現分離,畫面不抖了,延遲感也是很好的。做了這些,我們還做了TCP換成UDP,在手機下面,弱網的情況下,TCP很難恢復,UDP本身作為游戲也有優勢,之前還用過其他的,沒有優化到最后,不是很理想,最后用了UDP來做。整體來說,在網絡好的情況下,它延遲也是很好的,在網絡比較差的情況下,做插值,網絡情況差的話,也是傳統cs的表現,我們經常見到角色A和B,有些客戶端A在左B在右,有些是A在右B在左,幀同步邏輯上面AB之間的距離和坐標都是完全一樣,但是畫面上看到他們可能會不重合,那就是你把它們分離之后的表現。網絡極其好的情況下,它應該是重合的,但是在網絡差的情況下,可能會有些偏差。這是里面最重要的一塊優化。
第三座大山是性能。下面是我們對性能優化,本身幀同步邏輯上面在優化上面存在一些缺點,所有的角色都需要進行運算。這里面還是用的Unity,里面也有很好的特性,如果你想追求性能上的極致,有些東西你需要尋求好的方式。
第一是熱點的處理,我們是不用反射的,它都有GC性能開銷,你可能經常會隱藏或者把它顯示出來,我們的做法里面,把對象的顯示隱藏放在不同的渲染層里面,盡量讓整個游戲幀率是平滑的過程。還有我們本身有自己的系統,還有AI,這樣的一個游戲類型里面的角色比較多,你如果想要做比較好,它的AI是比較復雜的。要去優化熱點,我覺得就只有這三個步驟可以走。
從程序的結構上面能找到更優的,它的效果是最明顯的,如果你的結構都是用的最好,就在挖掘局部的算法,調整你代碼的一些寫法。如果局部的算法都已經調到最優還是沒有什么辦法,那只有一條路,就是犧牲整個質量,就是分幀降頻。
第二點是GC,這塊剛才說不用反射,還有裝箱和拆箱的行為也是盡量少用。Unity指導過我們的優化,從GC上面的考慮,他們建議每一幀應該在200個字節以內是比較好的狀態,其實很難做到,王者也是每一幀在1k左右,很難做到200。
第三是Drawcall,這些傳統的優化手段大家都用的很熟了。
第四是裁剪,幀同步里面是不能裁剪的,表現里面我看不到的可以降低頻率或者不更新它,這在表現里面可以做的。
第五點是3DUI。《王者榮耀》的血條、小地圖上面疊的元素比較多,比較豐富,這塊我們用了31UI的方式來優化,沒有用UGUI里面進行血條方面的處理。我們也犧牲了一些東西,我們把所有東西都加載了,在游戲過程當中,我們希望不要有任何IO行為,包括輸出我們都是要布局的。你處理的決策和復雜度,如果在一幀里面放出100顆×××,在放100顆×××的時候一定要掉幀的,一定要在力所能及的時候把這些東西做到極致。
前面提的是第一代,去年5月份以前做的優化方案。5月份的時候我們還做了另外一件事情:GameCore。
首先,為什么覺得IOS比安卓高一些,本身一個是IOS的CPU架構包括系統確實都優化的比較好,另外我們用的Unity4.6,在IOS下面它本身效率高一些,在安卓端的機器各種各樣,性能也是千差萬別,我們只能用性能比較差的方式。因為本身已經做到邏輯和表現是分離的,我們能不能把邏輯獨立出來,做成一個C++的東西,我們在去年開始這樣做了。做之前也測試過C++和Mono性能的差別,大概是2.5左右,本身我們的邏輯占比游戲消耗20%多,邏輯不是一個大頭,我們做了GameCore之后,還是有效的,幀率提升了2到3幀,花的時間很長。整個時間大部分都消耗在了引擎和CPU的交互、調度,
其次,做GameCore最顯著的變化是我們以前邏輯上的GC沒有了,我們有自己內存的管理、對象的管理,包括里面所有的容器類這些東西都是我們自己實現的,包括反射整個一套。它有了自己的內存管理,它本身效率就比較高,其實還是一個比較明顯的優勢,
再次,有了GameCore之后,有很多應用場景,這個東西就是玩法的服務器版本,應用場景運行服務器要做很多的分析,還有第三方使用都是可以的。
最后,GameCore可以做成一個多線程的話。
“王者”前方的路
我們接下來看一下我們后面可能打算考慮的一些事情。
第一,是我們想能不能在熱更新上面有所突破。因為王者這樣一個游戲類型,包括它的體量,我們對于性能有一個比較極致的追求,不會輕易使用腳本層面在性能層面本身就不是最好的。這個我們要去研究的就是熱更新,性能最好的方式。
第二,我們也在和硬件廠商溝通,他們其實也是希望游戲能夠真正發揮多核性能上的優勢,大部分的游戲在單核上面,把一個核吃的滿滿的,很多時候我們現在得出的結論,GPU性能也很強,王者并沒有對GPU占滿,可能只用了30%,CPU反而吃的比較滿,吃滿以后它還有另外一個壞處,它的發熱、降頻,你如果用多線程、多核去盡量平坦,讓它不要處于高頻的工作方式,反而會有更好的效果。
第三,我們現在用Unity4.6,Unity進化到5.7,后面他們還會推出新的特性,我們希望結合一些Unity新特性,現在已經有些游戲用5.6可以提升性能。不光是提升性能問題,Unity在多線程的渲染,也有很好的作用,使用引擎優勢也是很必要的。
第四,隨著性能的提升,我們會對王者的畫質進行提升。
今天我的分享就到這里。
轉載于:https://blog.51cto.com/unitysky/1926609
總結
以上是生活随笔為你收集整理的腾讯邓君:《王者荣耀》翻过的同步技术相关的三座大山的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 干货 | OneAPM研发总监高海强:百
- 下一篇: MySQL 到PostgreSQL 的数