網(wǎng)絡(luò)游戲同步問題

文章是我轉(zhuǎn)載的,沒找到原作者地址。

介紹

作為一個(gè)程序,你想過網(wǎng)絡(luò)多人對(duì)戰(zhàn)游戲是怎么做出來的嗎?

從外行的角度來看多人對(duì)戰(zhàn)游戲是很神奇的:2個(gè)或者更多的玩家在同一個(gè)時(shí)間經(jīng)歷了相似的游戲經(jīng)歷,感覺他們就像在同一個(gè)虛擬世界中游戲一樣。但是作為程序員我們卻知道事實(shí)并不是他們想象的那樣的,他們看到的絕大多數(shù)其實(shí)都是假象。他們所認(rèn)為玩家間同時(shí)經(jīng)歷的很多事件其實(shí)只是一種逼真的模擬。不同玩家間或多或少會(huì)存在不同步,程序員就是讓這些不同步在玩家眼中變得同步起來。 by rellikt

P2P的回合類通信游戲

最開始的時(shí)候游戲的網(wǎng)絡(luò)拓?fù)淠P褪荘2P結(jié)構(gòu)的,所有的機(jī)器都是P2P網(wǎng)絡(luò)中等價(jià)的節(jié)點(diǎn),他們互相發(fā)送需要的信息,不需要任何中轉(zhuǎn)。這種網(wǎng)絡(luò)拓?fù)淠P驮诤芏郣TS游戲中還很常見,甚至很多程序員在思考網(wǎng)絡(luò)的時(shí)候第一個(gè)想到的模型就是這個(gè)模型,因?yàn)檫@個(gè)模型和我們平時(shí)人與人間的交流模型的確很像。by rellikt

這個(gè)模型的基礎(chǔ)思路是把游戲抽象成為一輪一輪的回合,在每個(gè)回合中把所有的輸入轉(zhuǎn)換成一個(gè)個(gè)指令,然后在每個(gè)回合的開始時(shí)候處理這些指令,這些指令導(dǎo)致的行為自然會(huì)推動(dòng)游戲狀態(tài)機(jī)的運(yùn)行。我們?cè)谝粋€(gè)類似SC的RTS中最常見的指令會(huì)有:移動(dòng),攻擊,建筑等。選用這個(gè)模型的話,我們只要保證所有的用戶都有相同的指令集,并且他們的初始狀態(tài)相同就不會(huì)有問題了。

以上這段介紹對(duì)于一個(gè)類似SC1的RTS游戲的網(wǎng)絡(luò)模塊來說,可能有點(diǎn)太過于簡(jiǎn)單了。事實(shí)上我也只是說了個(gè)大概的概念,如果你有興趣可以參考這篇介紹帝國時(shí)代的論文。

以上提到的網(wǎng)絡(luò)拓?fù)淠P涂瓷先サ拇_是簡(jiǎn)單實(shí)用,但是同時(shí)這個(gè)模型的簡(jiǎn)單也帶來了以下的一些限制:

這個(gè)模型的在可重演性上是要求相當(dāng)高的:因?yàn)槲覀冎回?fù)責(zé)指令的同步,不負(fù)責(zé)指令具體運(yùn)行結(jié)果的同步,我們很可能會(huì)發(fā)現(xiàn)因?yàn)橐粋€(gè)步兵在尋路的時(shí)候稍微走的有點(diǎn)不一樣的地方,就導(dǎo)致了一場(chǎng)戰(zhàn)斗的結(jié)果大不相同。而這樣情況導(dǎo)致的蝴蝶效應(yīng)已經(jīng)足夠讓我們游戲體驗(yàn)崩潰了。 by rellikt

這個(gè)模型的第二個(gè)缺點(diǎn)就是必須保證在一回合開始的時(shí)候,所有玩家的指令都已經(jīng)到齊,不然這回合的指令就無法開始模擬。這就是說,所有玩家的延遲其實(shí)是取決于延遲最大的玩家的延遲。RTS為了解決這個(gè)問題,通常會(huì)設(shè)置一些前搖動(dòng)畫和音樂來讓玩家以為指令已經(jīng)開始模擬了,但是實(shí)際上真正指令開始模擬的時(shí)間肯定是會(huì)和玩家輸入時(shí)間有延遲的。這些偽裝對(duì)玩家很好的掩蓋了這點(diǎn)。

這個(gè)模型的最后一個(gè)缺點(diǎn)就是玩家必須從一開始就加入游戲。也就是說通常這里游戲的模式是在大廳中開一個(gè)房間,然后玩家加入游戲開始玩,這種模式不會(huì)允許玩家中途加入。雖然把從開始到中途加入這段時(shí)間的指令存起來,然后讓想加入的玩家進(jìn)行模擬,然后再加入是一種在理論上可行的解決方案,但是這個(gè)方案牽涉到的問題對(duì)游戲中的可預(yù)測(cè)性,可同步性的要求非常高,另外指令多了模擬時(shí)間也是問題,至少現(xiàn)在還沒看到哪個(gè)這類模型的游戲做出了類似的嘗試。 by rellikt

盡管我們上面提到的這個(gè)模型有種種令人不滿意的缺點(diǎn),但是在現(xiàn)實(shí)中的RTS游戲(比如星際1,紅警1,帝國1)里面基本都采用了這個(gè)模型,因?yàn)檫@類游戲中我們會(huì)操作成千上萬的單位,要一個(gè)個(gè)的去同步每個(gè)單位的狀態(tài)是不科學(xué)的,我們只能去同步指令,然后通過指令去同步游戲,推動(dòng)游戲狀態(tài)機(jī)的正常運(yùn)行。

事實(shí)上在最新的RTS游戲中可能已經(jīng)拋棄了P2P模式,但是回合類通信的概念還是會(huì)得到保留,否則是無法完成成千上萬個(gè)單位的同步的。

但是時(shí)代在進(jìn)步,游戲的類型也是千差萬別的。原始的P2P的回合制在現(xiàn)代的很多其他類型游戲中已經(jīng)基本被拋棄了。接下來我們來看看在Unreal,Quake,Doom中引入的FPS游戲的網(wǎng)絡(luò)模型吧。

客戶端/服務(wù)器端模型(C/S)

在最初的Quake游戲中,Doom采用的也是P2P的回合制通信模型,結(jié)果發(fā)現(xiàn)除了局域網(wǎng)低延遲高帶寬的情況,其他的情況下游戲性都不能讓人滿意。by rellikt

事實(shí)上,玩家的確可以通過虛擬局域網(wǎng)的軟件來模擬局域網(wǎng),然后通過局域網(wǎng)的模式進(jìn)行連接。但是連接的情況實(shí)在是很悲催。那些用蜘蛛網(wǎng)上網(wǎng)的玩家就不提了(14.4kbps PPP connection或28.8kbps貓上網(wǎng))。他們肯定是最杯具的。就是有寬帶的玩家也不見得能好到那里去。因?yàn)镻2P模型帶來的高延遲在FPS類游戲中是無法被很好的掩蓋的,對(duì)玩家輸入的正式模擬必須等到所有玩家的指令到達(dá)以后才能處理,也就是說你的延遲取決于當(dāng)前玩家中延遲最爛的那個(gè),如果說你的隊(duì)友中有300ms延遲的,那么你點(diǎn)一下射擊鍵,就得過300ms以后才才會(huì)做出射擊模擬。這樣的情況讓很多網(wǎng)絡(luò)不好的玩家只能望洋興嘆了。

為了讓更多網(wǎng)絡(luò)不好的玩家也能正常的玩。1996年,John Carmack在推出Quake的時(shí)候使用了C/S架構(gòu)取代掉了傳統(tǒng)的P2P架構(gòu)。C/S架構(gòu)和P2P架構(gòu)不同,P2P在每個(gè)客戶端都會(huì)運(yùn)行游戲邏輯,游戲顯示等完整的游戲,因此P2P對(duì)于游戲的可重演性要求是相當(dāng)高的。C/S架構(gòu)的概念就是在服務(wù)器端跑所有的游戲邏輯和輸入響應(yīng),在客戶端只跑所有的游戲顯示,這樣的話客戶端只需要把自己需要的一些狀態(tài)同步下來,把用戶輸入發(fā)給服務(wù)器端,然后顯示結(jié)果就可以了。 by rellikt

拿傳統(tǒng)的FPS來說,理想的C/S結(jié)構(gòu)中,客戶端只需要發(fā)送自己的輸入比如移動(dòng),轉(zhuǎn)身,開火給服務(wù)器端,然后再從服務(wù)器端把自己和周圍可見玩家的位置,朝向,動(dòng)畫狀態(tài)等信息同步下來,做一下合理的插值,使其各個(gè)角色看起來足夠流暢,然后顯示出來。一個(gè)基本C/S架構(gòu)的FPS就完成了。

比較一下上面兩個(gè)模型,我們發(fā)現(xiàn)C/S架構(gòu)最大的優(yōu)點(diǎn)就是把延遲從最卡的玩家的延遲改變?yōu)楹头?wù)器連接的延遲。另外使用這個(gè)架構(gòu)中途加入玩家的概念也很容易就能實(shí)現(xiàn)了。最后在發(fā)包上面來說,在帶寬上的要求也低了不少。只需要把輸入發(fā)給服務(wù)器端就夠了。

但是純理想的C/S模型還是有不足的地方,那就是延遲,F(xiàn)PS對(duì)于延遲的要求是相當(dāng)高的,互聯(lián)網(wǎng)上兩個(gè)端點(diǎn)間的lag有300ms是很正常的,如果說一個(gè)轉(zhuǎn)身指令要等300ms以后才能響應(yīng)的話,以9s/m跑步的速度來算,玩家就已經(jīng)跑出將近3m了,也許早就掉到溝里面去了。

為了讓更多使用爛網(wǎng)絡(luò)的玩家能夠加入到游戲中,John Carmark在推出Quake的時(shí)候也引入了客戶端預(yù)測(cè)的新技術(shù)。by rellikt

客戶端預(yù)測(cè)

其實(shí)在早期的FPS游戲中,我們的確會(huì)碰到按一個(gè)鍵要等半天才能反應(yīng)的情況,而這個(gè)時(shí)間就是和你的網(wǎng)絡(luò)延遲有關(guān)的,有些強(qiáng)的玩家甚至能夠適應(yīng)這種情況,提前做出預(yù)判操作。但是在現(xiàn)代的FPS游戲比如COD等游戲中,你已經(jīng)再也不會(huì)有這種體驗(yàn)了,那我們現(xiàn)代的FPS游戲是用什么手段來移除這些延遲的呢?

這部分的技術(shù)一般分兩塊:客戶端預(yù)測(cè)和延遲補(bǔ)償。這些技術(shù)在Unreal引擎中的網(wǎng)絡(luò)部分中都有介紹。這里我們著重先討論一下關(guān)于客戶端預(yù)測(cè)的概念。

John Carmack在推出Quake的時(shí)候提到:我會(huì)在新的Quake中引入客戶端預(yù)測(cè)的概念,也就是說客戶端不只是簡(jiǎn)單做一些同步和顯示。他們還會(huì)做預(yù)測(cè),也就是說在得到服務(wù)器端數(shù)據(jù)之前,客戶端就會(huì)預(yù)先對(duì)輸入的結(jié)果做預(yù)測(cè)并且預(yù)測(cè)其他可見玩家的行動(dòng),并且立即進(jìn)行顯示,這會(huì)使得現(xiàn)在的客戶端需要物理,游戲邏輯在本地運(yùn)行。原本完美的C/S模型在這里就顯得不那么完美,但是還是讓我們面對(duì)現(xiàn)實(shí)吧,現(xiàn)實(shí)本來就不完美。by rellikt

我們現(xiàn)在的情況就是客戶端在接受到本地輸入以后會(huì)直接運(yùn)行一部分的游戲邏輯代碼,對(duì)用戶狀態(tài)進(jìn)行判斷,然后進(jìn)行模擬,再顯示出來,客戶端不會(huì)等到服務(wù)器端的數(shù)據(jù)到達(dá)以后再進(jìn)行模擬了,這樣說來對(duì)客戶端來說延遲已經(jīng)不存在了。

但對(duì)于客戶端預(yù)測(cè)來說,重點(diǎn)其實(shí)不在預(yù)測(cè)上,而是在同步上。我們只需要使用相同的代碼,預(yù)測(cè)自然就不會(huì)有問題了。但是當(dāng)服務(wù)器和客戶端對(duì)于結(jié)果出現(xiàn)分歧的時(shí)候怎么同步就是一個(gè)大問題了。

談到這里你就會(huì)想,如果說客戶端已經(jīng)預(yù)測(cè)了游戲的進(jìn)程,為什么不讓服務(wù)器端去同步客戶端的結(jié)果呢?這樣的方案看上去是不錯(cuò)的,但是附帶而來的作弊問題卻是很嚴(yán)重的,如果服務(wù)器不進(jìn)行模擬,而是簡(jiǎn)單的同步玩家狀態(tài),那么瞬移,無敵等外掛就會(huì)很常見了。玩家只需要模擬這些,發(fā)出對(duì)應(yīng)的包就可以了?,F(xiàn)在流行的許多MMORPG中的外掛就是這種同步而產(chǎn)生的結(jié)果。事實(shí)上由于對(duì)于服務(wù)器性能上的考慮,MMO中往往只會(huì)最簡(jiǎn)單同步一些狀態(tài)信息和事件信息。 by rellikt

因此在Unreal的實(shí)現(xiàn)中Tim Sweency決定讓服務(wù)器和客戶端分別模擬游戲,來實(shí)現(xiàn)用戶端預(yù)測(cè)來消除延遲。Tim Sweency在Unreal Networking Architecture中寫道“The Server is The Man”.

既然這樣的話,我們很容易想到一個(gè)有趣的問題。我們的原則是用戶狀態(tài)以服務(wù)器模擬為準(zhǔn),客戶端必須即時(shí)同步服務(wù)器上的狀態(tài),使自己的行為和服務(wù)器上的一致?,F(xiàn)在的問題是:由于延遲是客觀存在的,所以服務(wù)器上的數(shù)據(jù)總是比客戶端的要慢。事實(shí)上客戶端能夠同步到的數(shù)據(jù)只能是ping值(數(shù)據(jù)包在客戶端和服務(wù)器端一個(gè)來回的時(shí)間)以前那個(gè)時(shí)間點(diǎn)的數(shù)據(jù)。

如果客戶端只是簡(jiǎn)單同步當(dāng)前獲得的服務(wù)器端的數(shù)據(jù),那么結(jié)果就是,客戶端會(huì)把ping值以前的狀態(tài)給同步回來,而做出的修改就正好是我們要做的客戶端預(yù)測(cè)的那部分,如果真的這么做,那么我們的客戶端預(yù)測(cè)就完全是無意義的存在了。by rellikt

這里Tim Sweency采用的方法是采用兩個(gè)環(huán)形的緩沖,一個(gè)記錄客戶端的狀態(tài),我們稱其為狀態(tài)緩沖,一個(gè)記錄客戶端的操作,我們稱其為操作緩沖,這兩個(gè)緩沖的長(zhǎng)度應(yīng)該長(zhǎng)到至少可以容納ping值這段時(shí)間的狀態(tài)和操作。我們每過一個(gè)固定的時(shí)間把客戶端狀態(tài)寫入狀態(tài)緩沖,每個(gè)操作都會(huì)被寫入操作緩沖。當(dāng)服務(wù)器端同步來的數(shù)據(jù)到達(dá)客戶端以后,我們先提取這個(gè)服務(wù)器端數(shù)據(jù)所帶時(shí)間點(diǎn),然后把這個(gè)時(shí)間點(diǎn)以前的數(shù)據(jù)從客戶端的兩個(gè)緩沖緩沖中釋放掉,然后再把狀態(tài)緩沖中最接近的那個(gè)時(shí)間點(diǎn)狀態(tài)數(shù)據(jù)提取出來,從那個(gè)狀態(tài)開始用操作緩沖中存的操作數(shù)據(jù)進(jìn)行操作模擬,最后得到現(xiàn)在的狀態(tài),再用得到的這個(gè)狀態(tài)來進(jìn)行插值,同步。事實(shí)上在客戶端為了消除延遲我們一直在進(jìn)行回滾然后重演的過程,這個(gè)ping值越大,我們需要回滾和重演的時(shí)間就越多,同時(shí)在得出的新狀態(tài)中可能需要插值和同步的幅度也會(huì)越大。

Unreal中就是這么處理延遲的,這個(gè)技巧運(yùn)用得當(dāng)?shù)脑?,可以很有效的把延遲給掩蓋掉。Tim Sweency在Unreal的白皮書中說,如果我們的游戲的可重演性越好,我們需要的插值就越少,甚至在其他客戶端和環(huán)境變量不變的情況下,我們是幾乎不需要任何的插值和修改的。事實(shí)上在Unreal中,往往只有撞上敵人或者被火箭彈打飛了才會(huì)用到插值修改。

換句話來說只要不涉及到其他玩家的操作或者有人作弊,那么我們采用的客戶端預(yù)測(cè)往往是很準(zhǔn)確的。by rellikt

結(jié)論

關(guān)于客戶端預(yù)測(cè)我現(xiàn)在只想談這么多了。如果下期有時(shí)間我會(huì)再寫一些關(guān)于延遲補(bǔ)償?shù)母拍罨蛘咴诒疚闹兄苯有薷?。就是延遲補(bǔ)償技術(shù)的存在,是用戶能在延遲的情況下照樣彈無虛發(fā),體驗(yàn)不到延遲的感覺

網(wǎng)絡(luò)游戲的位置同步問題

有關(guān)位置同步的方案實(shí)際上已經(jīng)比較成熟,網(wǎng)上也有比較多的資料可供參考。在《帶寬限制下的視覺實(shí)體屬性傳播》一文中,作者也簡(jiǎn)單提到了位置同步方案的構(gòu)造過程,但涉及到細(xì)節(jié)的地方?jīng)]有深入,這里專門針對(duì)這一主題做些回顧。

最直接的同步方案就是客戶端在每次發(fā)生位置改變時(shí)都向服務(wù)器報(bào)告 ,服務(wù)器再轉(zhuǎn)發(fā)給周圍的其他玩家,其他客戶端將對(duì)應(yīng)的游戲?qū)嶓w移動(dòng)到新的位置上。

但是這樣存在一個(gè)問題,每個(gè)玩家的位置都是自己先開始移動(dòng),一段時(shí)間之后才在其他玩家的客戶端上表現(xiàn)出來。如果只是希望每個(gè)客戶端上看到的游戲?qū)ο蠖纪瑫r(shí)開始移動(dòng),那可以讓玩家的每一步操作都由服務(wù)器確認(rèn)之后再執(zhí)行,這樣誤差將縮減到不同客戶端之間的網(wǎng)絡(luò)延時(shí)差。但是顯然的,這樣的做法不可能真正被采用,因?yàn)檫@將使得玩家的游戲體驗(yàn)非常的糟糕。有誰能忍受連每走一步路都要卡一下的游戲呢?

既然一定存在先后時(shí)間差,那需要一種方法來讓不同客戶端上看到的玩家位置不至于有太大的誤差,尤其是不能有影響到游戲公平性的誤差存在。根據(jù)誤差出現(xiàn)的直接原因:時(shí)間差,我們應(yīng)該能夠想到一個(gè)解決方案,那就是讓其他客戶端設(shè)法彌補(bǔ)掉這段時(shí)間差內(nèi)少走的距離。這樣的話也就要求我們的消息包中多帶一個(gè)開始移動(dòng)的時(shí)間數(shù)據(jù),用于其他客戶端在收到這個(gè)消息包時(shí)計(jì)算對(duì)應(yīng)的玩家實(shí)體已經(jīng)移動(dòng)過的時(shí)間和距離。

我們以一個(gè)實(shí)際的例子來說明如何減少這種誤差的影響。假設(shè)玩家A以速度V從P1點(diǎn)去到P2點(diǎn),A的網(wǎng)絡(luò)延時(shí)為T1,在A旁邊有個(gè)玩家B,他的網(wǎng)絡(luò)延時(shí)為T2.B收到服務(wù)器轉(zhuǎn)發(fā)過來的移動(dòng)包時(shí),A在其自己的客戶端上已經(jīng)移動(dòng)了T1+T2的時(shí)間,在這段時(shí)間內(nèi)他自己已經(jīng)走過了V*(T1+T2)的距離。如果這時(shí)在B的客戶端上開始將實(shí)體A從P1移動(dòng)到P2,那顯然兩個(gè)客戶端上看到的A的位置始終存在V*(T1+T2)的誤差。

為了使A在B客戶端上顯示的位置與其實(shí)際位置的誤差盡可能的縮小,一個(gè)簡(jiǎn)單的做法是直接將A的位置向前拖V*(T1+T2)然后開始移動(dòng),這樣兩者之間的誤差便消除了。但這樣會(huì)使得客戶端的顯示太魯莽,要讓其看起來平滑一些,我們可以考慮使用一些算法,比如計(jì)算出A從當(dāng)前位置走到P2點(diǎn)還需要的時(shí)間,然后加快其速度使其在規(guī)定的時(shí)間內(nèi)到達(dá)P2點(diǎn),這樣A和B看到的最終時(shí)間是相同的,但中間過程還是存在較多誤差。另一種較好的做法是先讓A以一個(gè)可接受的較快速度移動(dòng)到其當(dāng)前應(yīng)該所在的位置稍前一點(diǎn)的地方,然后以正常速度移動(dòng)到P2點(diǎn),這樣后面的移動(dòng)情況與其實(shí)際移動(dòng)情況基本吻合了。

看起來這個(gè)方案很完美,但是這里卻忽略了一個(gè)問題:我們假設(shè)的是每次移動(dòng)時(shí)都知道玩家要去的確切位置。這在靠鼠標(biāo)點(diǎn)擊來移動(dòng)的2D游戲中是正好合適的,但是在WOW一類的靠鍵盤來移動(dòng)的3D游戲中卻沒有辦法采用。WOW中的移動(dòng)消息都只能向服務(wù)器報(bào)告當(dāng)前的坐標(biāo)及朝向信息。

這類移動(dòng)的位置同步其實(shí)也可以采用類似方案,服務(wù)器將移動(dòng)玩家的當(dāng)前位置信息廣播給周圍的其他玩家,當(dāng)然其中也包含了時(shí)間戳。當(dāng)其他玩家收到這個(gè)移動(dòng)包后,表示的是在過去的某個(gè)時(shí)間里該玩家移動(dòng)到了這個(gè)位置。如果只是簡(jiǎn)單地將其對(duì)應(yīng)的實(shí)體移動(dòng)到這個(gè)位置,那同樣的,也存在位置誤差。

與上一種情況類似,如果我們知道該玩家的移動(dòng)速度,再通過數(shù)據(jù)包中的時(shí)間戳,假設(shè)該玩家還在以相同的速度朝相同的方向移動(dòng),那我們也可以預(yù)測(cè)出該玩家從開始移動(dòng)到現(xiàn)在這段時(shí)間內(nèi)他走了多遠(yuǎn)了距離。我們也可以將其位置做適當(dāng)?shù)男拚⑹蛊淅^續(xù)移動(dòng)下去。

我們需要先停下來考慮一下這些算法的部分細(xì)節(jié)。其中出現(xiàn)了一些數(shù)據(jù)是否應(yīng)該包含在我們的每個(gè)消息包中,也就是我們需要考慮的另外一個(gè)問題:移動(dòng)同步的消息中應(yīng)該包含哪些數(shù)據(jù),以及這些數(shù)據(jù)到底應(yīng)該向哪些玩家廣播。

對(duì)于2D游戲的情況來說,我們的算法需要的數(shù)據(jù)有:玩家的速度V,玩家開始移動(dòng)的時(shí)間T0,收到數(shù)據(jù)包的時(shí)間T1,玩家當(dāng)前位置P1和玩家要去的位置P2.T1和P1從當(dāng)前客戶端上都可以取到,而速度V一般來說不會(huì)經(jīng)常改變,至少不是每次移動(dòng)時(shí)都不一樣,所以我們可以為速度的改變?cè)O(shè)計(jì)單獨(dú)的消息碼,這樣V值也是可以在客戶端上取到的。最后,每個(gè)移動(dòng)消息中包含的數(shù)據(jù)只需要有移動(dòng)到的位置P2和開始移動(dòng)的時(shí)間T0.

其他客戶端在使用特定算法將玩家移動(dòng)到P2后會(huì)將其停在此處,直到收到下一個(gè)移動(dòng)包時(shí)再開始移動(dòng)。而對(duì)于在移動(dòng)過程中又收到了新的移動(dòng)包的處理過程基本類似,不做過多描述。

對(duì)于3D游戲的情況,算法是基本相同的,但是沒有目標(biāo)點(diǎn),替換為移動(dòng)方向,比如是向正前方移動(dòng),還是向左或向右移動(dòng)等。在這種情況下,只要沒有收到玩家停止移動(dòng)的消息,其他客戶端上都會(huì)以最后一次收到的移動(dòng)包的狀態(tài)來繼續(xù)模擬移動(dòng)。

所以,在網(wǎng)絡(luò)偶爾卡一下的時(shí)候也會(huì)出現(xiàn)一些奇怪的現(xiàn)象。比如WOW中,看到隊(duì)友直沖沖地走下了懸崖,你剛喊了句“怎么掉下去了?”只見隊(duì)友又從身后走出來,還冒出一句:“沒啊,我就在你旁邊!”

關(guān)于數(shù)據(jù)要向哪些人廣播的問題,其實(shí)很簡(jiǎn)單,哪些人會(huì)看到這個(gè)玩家就需要向哪些人廣播。不管是直接在主屏幕上看到還是在大地圖上看到的代表其位置的一個(gè)點(diǎn)。但是,針對(duì)不同的人使用的廣播策略還是存在差異。

在《帶寬限制下的視覺實(shí)體屬性傳播》一文中提出了一個(gè)方案很值得參考。該方案提出的基礎(chǔ)是因?yàn)?D空間透視的原因,離你很遠(yuǎn)的一個(gè)玩家移動(dòng)了10米,最終在你的顯示器上看到的位移可能只有一個(gè)象素;而離你不到一米的一個(gè)玩家雖然只移動(dòng)了一米,但最終顯示出來的位移可能會(huì)有幾十個(gè)象素。所以,遠(yuǎn)處玩家的移動(dòng)并不需要非常嚴(yán)格的關(guān)注,但近處玩家的移動(dòng)同步需要非常高的優(yōu)先級(jí)。

這個(gè)方案的實(shí)現(xiàn)還依賴于另一項(xiàng)技術(shù)要求,玩家的屬性更新以一定的頻率來進(jìn)行,更新時(shí)比較一下當(dāng)前屬性值與上次更新時(shí)的屬性值,如果存在差異則通知客戶端更新,另外如果中間跳過了某次更新也不會(huì)對(duì)客戶端表現(xiàn)及游戲公平性造成什么影響。比如這里要處理的玩家坐標(biāo),第一次移動(dòng)到A點(diǎn),第二次從A點(diǎn)又移動(dòng)到B點(diǎn),如果移動(dòng)到A點(diǎn)的更新包沒有發(fā)送,直接發(fā)送了移動(dòng)到B點(diǎn)的更新包,這將不會(huì)對(duì)游戲邏輯產(chǎn)生大的影響。

這套方案基本上是為3D游戲的實(shí)體屬性廣播優(yōu)化而設(shè)計(jì)的,在2D游戲中很難使用。一是斜45度視角的2D游戲中屏幕頂端、中間和底部任何一個(gè)位置上的玩家移動(dòng),其距離和象素比是完全相同的,因?yàn)楫嬅娌淮嬖谕敢?,所以也就沒有遠(yuǎn)處對(duì)象更新頻率低這一可能。另外2D游戲中的移動(dòng)與3D游戲也存在差異,具體情況前面有詳細(xì)描述,2D游戲中基本上每一次移動(dòng)都需要廣播,不能跳過哪一個(gè),否則玩家看到的現(xiàn)象就是在亂跑,這也必將影響到技能的使用等游戲邏輯。

有關(guān)位置同步所涉及到的一些技術(shù)細(xì)節(jié)及優(yōu)化方案上面描述了一部分,但是在實(shí)際的應(yīng)用中是否會(huì)使用還是要看具體游戲的需求。比如大話類型的游戲,其本身對(duì)位置的精確同步就沒有要求,兩個(gè)客戶端上出現(xiàn)一前一后的移動(dòng)也不會(huì)影響任何的游戲邏輯,所以前面提到的同步方案可能都用不上。

而對(duì)于一些同步要求很高的游戲,如WOW中盜賊這類職業(yè)的需求,上面的方案可能還不夠細(xì)致,還需要設(shè)計(jì)更加有效的同步方案。

另外,在位置同步過程中還有一個(gè)不容忽視的問題是外掛。我們不能像WOW那樣完全依賴客戶端,如果沒有暴雪那樣強(qiáng)硬的封號(hào)措施,游戲也就成為了外掛們的溫床。所以,如何在服務(wù)器端模擬每個(gè)客戶端的移動(dòng),如何檢測(cè)出客戶端是否存在作弊行為,也是需要重點(diǎn)關(guān)注的一個(gè)問題。

點(diǎn)擊這里可以看到作者的其他文章

歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)標(biāo)明出處: http://www.itdecent.cn/p/b4afda371729


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容