看到這篇文章的時(shí)候,我覺(jué)得很驚訝,雖然我對(duì)這方面的了解并不多,但在自己的想像中,還是對(duì)網(wǎng)游這些東西稍有一點(diǎn)想法,因?yàn)樵?jīng)有朋友做過(guò)簡(jiǎn)單的外掛,比如,抓包發(fā)包然后嘗試模擬包,來(lái)使網(wǎng)游達(dá)到你想實(shí)現(xiàn)的效果。
外掛這東西,在2003年左右應(yīng)該是一個(gè)巔峰吧,那時(shí)候,奇跡外掛、傳奇外掛,確實(shí)讓一部分人先富起來(lái),可是后來(lái)的零點(diǎn)行動(dòng),這些人都永遠(yuǎn)的消失在外掛長(zhǎng)河中。
那時(shí)候我就在想,外掛是什么原理,為什么我這邊的動(dòng)作,可以讓服務(wù)端產(chǎn)生那樣的效果?其實(shí),這就是一個(gè)同步的問(wèn)題,我個(gè)人理解是服務(wù)器上有個(gè)觸發(fā)器,這邊發(fā)包后,然后那邊判斷包是否正常,然后就會(huì)有一個(gè)相應(yīng)的動(dòng)作。當(dāng)然,動(dòng)作程序還是在本機(jī)上,地圖也在本機(jī)上,發(fā)出去的包,只是告訴服務(wù)器我是這樣在動(dòng)作的。于是就出現(xiàn)了瞬移,卡點(diǎn)這種情況,因?yàn)榘l(fā)出去的包,和坐標(biāo)位置在服務(wù)器上都是正常的。(以上是我的猜測(cè))
下面是文章:
不知道大家是否碰到過(guò)這種情況,當(dāng)某個(gè)玩家發(fā)出一個(gè)火球,這個(gè)火球有自己的運(yùn)動(dòng)軌跡,那么如何來(lái)判斷火球是否打中了人呢?大部分情況,當(dāng)策劃提出這個(gè)要求的時(shí)候,一般會(huì)被程序否認(rèn),原因是:太麻煩了,呵呵。復(fù)雜點(diǎn)的還有包括兩個(gè)火球相撞之類(lèi)的事情發(fā)生。
那么網(wǎng)絡(luò)游戲中,是否真的無(wú)法模擬實(shí)現(xiàn)這種模擬呢?
首先我們來(lái)看看模擬此種操作會(huì)帶來(lái)什么樣的麻煩:
1,服務(wù)器必須trace火球的運(yùn)行軌跡,乍一想,挺慢的。
2,網(wǎng)絡(luò)延遲,傳過(guò)來(lái)有延遲,傳過(guò)去有延遲,延遲還不穩(wěn)定,麻煩。
3,都有兩點(diǎn)解決不了了,接下來(lái)不愿意再想了。
呵呵,實(shí)際上呢,對(duì)火球的模擬比對(duì)人物運(yùn)動(dòng)的模擬要輕松很多,原因很簡(jiǎn)單,火球的方向不會(huì)變。下面來(lái)看看具體用什么樣的結(jié)構(gòu)來(lái)實(shí)現(xiàn):
不知道大家是否還記得我去年這個(gè)時(shí)候提到過(guò)的Dead Reckoning算法,我們要模擬火球運(yùn)動(dòng)的關(guān)鍵就在于一個(gè)叫Moving Objects Tracing Server的服務(wù)器程序,這個(gè)服務(wù)器是干什么的呢。這個(gè)服務(wù)器接收主游戲服務(wù)器發(fā)過(guò)來(lái)的注冊(cè)事件的信息,比如有個(gè)玩家,開(kāi)始移動(dòng)了,那么主游戲服務(wù)器就 把該玩家的運(yùn)動(dòng)PDU,包括方向,速度,加速度,起點(diǎn)發(fā)給MOTS (Moving Objects Tracing Server),然后MOTS自己開(kāi)始對(duì)其運(yùn)行進(jìn)行模擬,當(dāng)游戲服務(wù)器發(fā)來(lái)第二個(gè)PDU包的時(shí)候,則對(duì)各個(gè)物件的位置進(jìn)行修正,并重新開(kāi)始模擬。那么,我 們模擬的目的是什么呢?當(dāng)然是發(fā)生某些事件,比如說(shuō)碰撞,或者掉入地圖的某個(gè)陷阱的時(shí)候,會(huì)將該事件回發(fā)給主邏輯服務(wù)器。然后邏輯服務(wù)器來(lái)處理該事件。
那么,對(duì)于火球的處理,也和處理其他玩家的同步一樣,當(dāng)接收到玩家的發(fā)火球的指令以后,產(chǎn)生一個(gè)火球,并指定其PDU信息,在MOTS上注冊(cè)該個(gè)運(yùn) 動(dòng)物 體。當(dāng)MOTS自行模擬到這個(gè)物體和其他玩家或者NPC物體產(chǎn)生碰撞,則通知主邏輯服務(wù)器,然后主邏輯服務(wù)器產(chǎn)生相應(yīng)的動(dòng)作。
那么關(guān)于延遲呢?有些人也許會(huì)說(shuō),比如說(shuō)前面有個(gè)火球,我本地操縱的小人其實(shí)躲過(guò)去了,但是因?yàn)榫W(wǎng)絡(luò)延遲,在服務(wù)器上我并沒(méi)有躲過(guò)去,那么怎么算? 呵呵, 不知道大家玩過(guò)星際沒(méi)有,有沒(méi)有發(fā)現(xiàn)在星際中玩多人連線(xiàn)模式的時(shí)候,有一點(diǎn)最特別的地方,就是控制一個(gè)小兵的時(shí)候,點(diǎn)了地圖上的某個(gè)位置,但是小兵并不會(huì) 馬上開(kāi)始移動(dòng),而是有一定的延遲,但是這一小點(diǎn)延遲并不能掩蓋星際的經(jīng)典,同樣的理論用到這里也成立。對(duì)于客戶(hù)端的控制,當(dāng)玩家操縱的主角改變PDU信息 的時(shí)候,確保信息發(fā)送到服務(wù)器之后,再開(kāi)始處理本地的操作指令,這樣就能保證本地的預(yù)測(cè)和服務(wù)器的預(yù)測(cè)幾乎是沒(méi)有什么誤差的,即使有很小的誤差產(chǎn)生,以服 務(wù)器為主,這樣玩家也不會(huì)有太大的抱怨。
————————————————————————————————————————-
網(wǎng)絡(luò)游戲同步詳解之一
同步在網(wǎng)絡(luò)游戲中是非常重要的,它保證了每個(gè)玩家在屏幕上看到的東西大體是一樣的。其實(shí)呢,解決同步問(wèn)題的最簡(jiǎn)單的方法就是把每個(gè)玩家的動(dòng)作都向其 他玩家廣播一遍,這里其實(shí)就存在兩個(gè)問(wèn)題:1,向哪些玩家廣播,廣播哪些消息。2,如果網(wǎng)絡(luò)延遲怎么辦。事實(shí)上呢,第一個(gè)問(wèn)題是個(gè)非常簡(jiǎn)單的問(wèn)題,不過(guò)之 所以我提出這個(gè)問(wèn)題來(lái),是提醒大家在設(shè)計(jì)自己的消息結(jié)構(gòu)的時(shí)候,需要把這個(gè)因素考慮進(jìn)去。而對(duì)于第二個(gè)問(wèn)題,則是一個(gè)挺麻煩的問(wèn)題,大家可以來(lái)看這么個(gè)例 子:
比如有一個(gè)玩家A向服務(wù)器發(fā)了條指令,說(shuō)我現(xiàn)在在P1點(diǎn),要去P2點(diǎn)。指令發(fā)出的時(shí)間是T0,服務(wù)器收到指令的時(shí)間是T1,然后向周?chē)耐婕覐V播這條 消息,消息的內(nèi)容是“玩家A從P1到P2”有一個(gè)在A附近的玩家B,收到服務(wù)器的這則廣播的消息的時(shí)間是T2,然后開(kāi)始在客戶(hù)端上畫(huà)圖,A從P1到P2 點(diǎn)。這個(gè)時(shí)候就存在一個(gè)不同步的問(wèn)題,玩家A和玩家B的屏幕上顯示的畫(huà)面相差了T2-T1的時(shí)間。這個(gè)時(shí)候怎么辦呢?
有個(gè)解決方案,我給它取名叫預(yù)測(cè)拉扯,雖然有些怪異了點(diǎn),不過(guò)基本上大家也能從字面上來(lái)理解它的意思。要解決這個(gè)問(wèn)題,首先要定義一個(gè)值叫:預(yù) 測(cè)誤差。然后需要在服務(wù)器端每個(gè)玩家連接的類(lèi)里面加一項(xiàng)屬性,叫TimeModified,然后在玩家登陸的時(shí)候,對(duì)客戶(hù)端的時(shí)間和服務(wù)器的時(shí)間進(jìn)行比 較,得出來(lái)的差值保存在TimeModified里面。還是上面的那個(gè)例子,服務(wù)器廣播消息的時(shí)候,就根據(jù)要廣播對(duì)象的TimeModified,計(jì)算出 一個(gè)客戶(hù)端的CurrentTime,然后在消息頭里面包含這個(gè)CurrentTime,然后再進(jìn)行廣播。并且同時(shí)在玩家A的客戶(hù)端本地建立一個(gè)隊(duì)列,保 存該條消息,只到獲得服務(wù)器驗(yàn)證就從未被驗(yàn)證的消息隊(duì)列里面將該消息刪除,如果驗(yàn)證失敗,則會(huì)被拉扯回P1點(diǎn)。然后當(dāng)玩家B收到了服務(wù)器發(fā)過(guò)來(lái)的消息“玩 家A從P1到P2”這個(gè)時(shí)候就檢查消息里面服務(wù)器發(fā)出的時(shí)間和本地時(shí)間做比較,如果大于定義的預(yù)測(cè)誤差,就算出在T2這個(gè)時(shí)間,玩家A的屏幕上走到的地點(diǎn) P3,然后把玩家B屏幕上的玩家A直接拉扯到P3,再繼續(xù)走下去,這樣就能保證同步。更進(jìn)一步,為了保證客戶(hù)端運(yùn)行起來(lái)更加smooth,我并不推薦直接 把玩家拉扯過(guò)去,而是算出P3偏后的一點(diǎn)P4,然后用(P4-P1)/T(P4-P3)來(lái)算出一個(gè)很快的速度S,然后讓玩家A用速度S快速移動(dòng)到P4,這 樣的處理方法是比較合理的,這種解決方案的原形在國(guó)際上被稱(chēng)為(Full plesiochronous),當(dāng)然,該原形被我篡改了很多來(lái)適應(yīng)網(wǎng)絡(luò)游戲的同步,所以而變成所謂的:預(yù)測(cè)拉扯。
另外一個(gè)解決方案,我給它取名叫驗(yàn)證同步,聽(tīng)名字也知道,大體的意思就是每條指令在經(jīng)過(guò) 服務(wù)器驗(yàn)證通過(guò)了以后再執(zhí)行動(dòng)作。具體的思路如下:首先 也需要在每個(gè)玩家連接類(lèi)型里面定義一個(gè) TimeModified,然后在客戶(hù)端響應(yīng)玩家鼠標(biāo)行走的同時(shí),客戶(hù)端并不會(huì)先行走動(dòng),而是發(fā)一條走路的指令給服務(wù)器,然后等待服務(wù)器的驗(yàn)證。服務(wù)器接 受到這條消息以后,進(jìn)行邏輯層的驗(yàn)證,然后計(jì)算出需要廣播的范圍,包括玩家A在內(nèi),根據(jù)各個(gè)客戶(hù)端不同的TimeModified生成不同的消息頭,開(kāi)始 廣播,這個(gè)時(shí)候這個(gè)玩家的走路信息就是完全同步的了。這個(gè)方法的優(yōu)點(diǎn)是能保證各個(gè)客戶(hù)端之間絕對(duì)的同步,缺點(diǎn)是當(dāng)網(wǎng)絡(luò)延遲比較大的時(shí)候,玩家的客戶(hù)端的行 為會(huì)變得比較不流暢,給玩家?guī)?lái)很不爽的感覺(jué)。該種解決方案的原形在國(guó)際上被稱(chēng)為(Hierarchical master-slave synchronization),80年代以后被廣泛應(yīng)用于網(wǎng)絡(luò)的各個(gè)領(lǐng)域。
最后一種解決方案是一種理想化的解決方案,在國(guó)際上被稱(chēng)為Mutual synchronization,是一種對(duì)未來(lái)網(wǎng)絡(luò)的前景的良好預(yù)測(cè)出來(lái)的解決方案。這里之所以要提這個(gè)方案,并不是說(shuō)我們已經(jīng)完全的實(shí)現(xiàn)了這種方案,而 只是在網(wǎng)絡(luò)游戲領(lǐng)域的某些方面應(yīng)用到這種方案的某些思想。我對(duì)該種方案取名為:半服務(wù)器同步。大體的設(shè)計(jì)思路如下:
首先客戶(hù)端需要在登陸世界的時(shí)候建立很多張廣播列表,這些列表在客戶(hù)端后臺(tái)和服務(wù)器要進(jìn)行不及時(shí)同步,之所以要建立多張列表,是因?yàn)橐獜V播的類(lèi) 型是不止一種的,比如說(shuō)有l(wèi)ocal message,有remote message,還有g(shù)lobal message 等等,這些列表都需要在客戶(hù)端登陸的時(shí)候根據(jù)服務(wù)器發(fā)過(guò)來(lái)的消息建立好。在建立列表的同時(shí),還需要獲得每個(gè)列表中廣播對(duì)象的TimeModified,并 且要維護(hù)一張完整的用戶(hù)狀態(tài)列表在后臺(tái),也是不及時(shí)的和服務(wù)器進(jìn)行同步,根據(jù)本地的用戶(hù)狀態(tài)表,可以做到一部分決策由客戶(hù)端自己來(lái)決定,當(dāng)客戶(hù)端發(fā)送這部 分決策的時(shí)候,則直接將最終決策發(fā)送到各個(gè)廣播列表里面的客戶(hù)端,并對(duì)其時(shí)間進(jìn)行校對(duì),保證每個(gè)客戶(hù)端在收到的消息的時(shí)間是和根據(jù)本地時(shí)間進(jìn)行校對(duì)過(guò)的。 那么再采用預(yù)測(cè)拉扯中提到過(guò)的計(jì)算提前量,提高速度行走過(guò)去的方法,將會(huì)使同步變得非常的smooth。該方案的優(yōu)點(diǎn)是不通過(guò)服務(wù)器,客戶(hù)端自己之間進(jìn)行 同步,大大的降低了由于網(wǎng)絡(luò)延遲而帶來(lái)的誤差,并且由于大部分決策都可以由客戶(hù)端來(lái)做,也大大的降低了服務(wù)器的資源。由此帶來(lái)的弊端就是由于消息和決策權(quán) 都放在客戶(hù)端本地,所以給外掛提供了很大的可乘之機(jī)。
綜合以上三種關(guān)于網(wǎng)絡(luò)同步派系的優(yōu)缺點(diǎn),綜合出一套關(guān)于網(wǎng)絡(luò)游戲傳輸同步的較完整的解決方案,我稱(chēng)它為綜合同步法(colligate synchronization)。大體設(shè)計(jì)思路如下:
首先將服務(wù)器需要同步的所有消息從劃分一個(gè)優(yōu)先等級(jí),然后按照3/4的比例劃分出重要消息和非重要消息,對(duì)于非重要消息,把決策權(quán)放在客戶(hù)端,在客戶(hù)端邏輯上建立相關(guān)的決策機(jī)構(gòu)和各種消息緩存區(qū),以及相關(guān)的消息緩存區(qū)管理機(jī)構(gòu),如下圖所示:
上圖簡(jiǎn)單說(shuō)明了對(duì)于非重要消息,客戶(hù)端的大體處理流程,其中有一個(gè)客戶(hù)端被動(dòng)行為值得大家注意,其中包括對(duì)服務(wù)器發(fā)過(guò)來(lái)的某些驗(yàn)證代碼做返回, 來(lái)確保消息緩存中的消息和服務(wù)器端是一致的,從而有效的防止外掛來(lái)篡改本地消息緩存。其中的消息來(lái)源是包括本地的客戶(hù)端響應(yīng)玩家的消息以及遠(yuǎn)程服務(wù)器傳遞 過(guò)來(lái)的消息。
對(duì)于重要消息,比如說(shuō)戰(zhàn)斗或者是某些牽扯到玩家一些比較敏感數(shù)據(jù)的操作,則采用另外一套方案,該方案首先需要在服務(wù)器和客戶(hù)端之間建立一套 Ping System,然后服務(wù)器保存和用戶(hù)的及時(shí)的ping值,當(dāng)ping比較小的時(shí)候,響應(yīng)玩家消息的同時(shí)先不進(jìn)行動(dòng)作,而是先把該消息反饋給服務(wù)器,并且阻 塞,服務(wù)器收到該消息,進(jìn)行邏輯驗(yàn)證之后向所有該詳細(xì)廣播的有效對(duì)象進(jìn)行廣播(包括消息發(fā)起者),然后客戶(hù)端收到該消息的驗(yàn)證,才開(kāi)始執(zhí)行動(dòng)作。而當(dāng) ping比較大的時(shí)候,客戶(hù)端響應(yīng)玩家消息的同時(shí)立刻進(jìn)行動(dòng)作,并且同時(shí)把該消息反饋給服務(wù)器,值得注意的是這個(gè)時(shí)候還需要在本地建立一個(gè)無(wú)驗(yàn)證消息的隊(duì) 列,把該消息入隊(duì),執(zhí)行動(dòng)作的同時(shí)等待服務(wù)器的驗(yàn)證,還需要保存當(dāng)前狀態(tài)。服務(wù)器收到客戶(hù)端的請(qǐng)求后,進(jìn)行邏輯驗(yàn)證,并把消息反饋到各個(gè)客戶(hù)端,帶上各個(gè) 客戶(hù)端校對(duì)過(guò)的本地時(shí)間。如果驗(yàn)證通過(guò)不過(guò),則通知消息發(fā)起者,該消息驗(yàn)證失敗,然后客戶(hù)端自動(dòng)把已經(jīng)在進(jìn)行中的動(dòng)作取消,恢復(fù)原來(lái)狀態(tài)。如果驗(yàn)證通過(guò), 則廣播到的各個(gè)客戶(hù)端根據(jù)從服務(wù)器獲得校對(duì)時(shí)間進(jìn)行對(duì)其進(jìn)行拉扯,保證在該行為完成之前完成同步。
至此,一個(gè)比較成熟的網(wǎng)絡(luò)游戲的同步機(jī)制已經(jīng)初步建立起來(lái)了,接下來(lái)的邏輯代碼就根據(jù)各自不同的游戲風(fēng)格以及側(cè)重點(diǎn)來(lái)寫(xiě)了。
同步是網(wǎng)絡(luò)游戲最重要的問(wèn)題,如何同步也牽扯到各個(gè)方面的問(wèn)題,比如說(shuō)游戲的規(guī)模,游戲的類(lèi)型以及各種各樣的方面,對(duì)于規(guī)模比較大的游戲,在同 步方面可以下很多的工夫,把消息分得十分的細(xì)膩,對(duì)于不同的消息采用不同的同步機(jī)制,而對(duì)于規(guī)模比較小的游戲,則可以采用大體上一樣的同步機(jī)制,究竟怎么 樣同步,沒(méi)有個(gè)定式,是需要根據(jù)自己的不同情況來(lái)做出不同的同步?jīng)Q策的網(wǎng)游同步算法之導(dǎo)航推測(cè)(Dead Reckoning)算法:
——————————————————————————————————————————
網(wǎng)絡(luò)游戲同步詳解之二
在了解該算法前,我們先來(lái)談?wù)勗撍惴ǖ囊恍┍尘百Y料。大家都知道,在網(wǎng)絡(luò)傳輸?shù)臅r(shí)候,延遲現(xiàn)象是很普遍的,而在基于Server/Client結(jié)構(gòu) 下的網(wǎng)絡(luò)游戲的同步也就成了很頭疼的問(wèn)題,在保證客戶(hù)端響應(yīng)用戶(hù)本地指令流暢的情況下,沒(méi)法有效的保證的同步的及時(shí)性。同樣,在軍方也有類(lèi)似的事情發(fā)生, 即使是同一LAN里面的機(jī)器,也會(huì)因?yàn)閭鬏數(shù)难舆t,導(dǎo)致一些運(yùn)算的失誤,介于此,美國(guó)國(guó)防部投入了大量的資金用于研究一種比較的好的方案來(lái)解決分布式系統(tǒng) 中的延遲問(wèn)題,特別是一個(gè)叫分布式模擬運(yùn)動(dòng)(Distributed Interactive Simulation)的系統(tǒng),這套系統(tǒng)呢,其中就提出了一套號(hào)稱(chēng)是Latency Hiding & Bandwidth Reduction的方案,命名為Dead Reckoning。呵呵,來(lái)頭很大吧,恩,那么我們下面就來(lái)看看這套系統(tǒng)的一些觀(guān)點(diǎn),以及我們?nèi)绾伟阉\(yùn)用到我們的網(wǎng)絡(luò)游戲的同步中。
首先,這套同步方案是基于我那篇《網(wǎng)絡(luò)游戲的同步》一文中的Mutual Synchronization同步方案的,也就是說(shuō),它并不是Server/Client結(jié)構(gòu)的,而是基于客戶(hù)端之間的同步的。下面我們先來(lái)說(shuō)一些本文中將用到的名詞概念:
網(wǎng)狀網(wǎng)絡(luò):客戶(hù)端之間構(gòu)成的網(wǎng)絡(luò)
節(jié)點(diǎn):網(wǎng)狀網(wǎng)絡(luò)中的每個(gè)客戶(hù)端
極限誤差:進(jìn)行同步的時(shí)候可能產(chǎn)生的誤差的極值
恩,在探討其原理的之前,我們先來(lái)看看我們需要一個(gè)什么樣的環(huán)境。首先,需要一個(gè)網(wǎng)狀網(wǎng)絡(luò),網(wǎng)狀網(wǎng)絡(luò)如何構(gòu)成呢?當(dāng)有新節(jié)點(diǎn)進(jìn)入的時(shí)候,通知該 網(wǎng)絡(luò)里面的所有節(jié)點(diǎn),各節(jié)點(diǎn)為該客戶(hù)端在本地創(chuàng)建一個(gè)副本,登出的時(shí)候,則通知所有節(jié)點(diǎn)銷(xiāo)毀本地關(guān)于該節(jié)點(diǎn)的副本。然后每個(gè)節(jié)點(diǎn)該保存一些什么數(shù)據(jù)呢?首 先有一個(gè)很重要的包需要保存,叫做協(xié)議數(shù)據(jù)包(PDU Protocol Data Unit),PDU包含節(jié)點(diǎn)的一些相關(guān)的運(yùn)動(dòng)信息,比如當(dāng)前位置,速度,運(yùn)動(dòng)方向,或者還有加速度等一些信息。除PDU之外,還有其他信息需要保存,比如 說(shuō)節(jié)點(diǎn)客戶(hù)端人物的HP,MP之類(lèi)的。然后,保證每個(gè)節(jié)點(diǎn)在最少8秒之內(nèi)要向其它節(jié)點(diǎn)廣播一次PDU信息。最后,設(shè)置一個(gè)極限誤差值。到此,其環(huán)境就算搭 建完成了。下面,我們就來(lái)看看相關(guān)的具體算法:
假設(shè)在節(jié)點(diǎn)A有一個(gè)小人(路人甲),開(kāi)始跑路了,這個(gè)時(shí)候,就像所有的節(jié)點(diǎn)廣播一次他的PDU信息,包括:速度(S),方向(O),加速度 (A)。那么所有的節(jié)點(diǎn)就開(kāi)始模擬路人甲的運(yùn)動(dòng)軌跡和路線(xiàn),包括節(jié)點(diǎn)A本身(這點(diǎn)很重要),同時(shí),路人甲在某某玩家的控制下,會(huì)不時(shí)的改變一下方向,讓其 跑路的路線(xiàn)變得不是那么正規(guī)。在跑路的過(guò)程中,節(jié)點(diǎn)A有一個(gè)值在不停的記錄著其真實(shí)坐標(biāo)和在后臺(tái)模擬運(yùn)動(dòng)的坐標(biāo)的差值,當(dāng)差值大于極限誤差的時(shí)候,則計(jì)算 出當(dāng)前的速度S,方向O和速度A(算法將在后面介紹),并廣播給網(wǎng)絡(luò)中其他所有節(jié)點(diǎn)。其他節(jié)點(diǎn)在收到這條消息之后呢,就可以用一些很平滑的移動(dòng)把路人甲拉 扯過(guò)去,然后重新調(diào)整模擬跑路的數(shù)據(jù),讓其繼續(xù)在后臺(tái)模擬跑路。
很顯然,如果極限誤差定義得大了,其他節(jié)點(diǎn)看到的偏差就會(huì)過(guò)大,如果極限偏差定義得小了,網(wǎng)絡(luò)帶寬就會(huì)增大。如果定義這個(gè)極限誤差,就該根據(jù)各 種數(shù)據(jù)的重要性來(lái)設(shè)計(jì)了。如果是回合制的網(wǎng)絡(luò)游戲,那么在走路上把極限誤差定義得大些無(wú)所謂,可以減少帶寬。但是如果是及時(shí)打斗的網(wǎng)絡(luò)游戲,那么就得把極 限誤差定義得小一些,否則會(huì)出現(xiàn)某人看到某人老遠(yuǎn)把自己給砍死的情況。
Dead Reckoning的主要算法有9種,但是只有兩種是解決主要問(wèn)題的,其他的基本上只是針對(duì)不同的坐標(biāo)系的一些不同的算法,這里就不一一介紹了。好,那么我們下面來(lái)看傳說(shuō)中的最主要的兩種算法:
第一:目標(biāo)點(diǎn) = 原點(diǎn) + 速度 * 時(shí)間差
第二:目標(biāo)點(diǎn) = 原點(diǎn) + 速度 * 時(shí)間差 + 1/2 * 加速度 * 時(shí)間差
呵呵,傳說(shuō)中的算法都是很經(jīng)典的,雖然我們?cè)缭诔踔形锢淼臅r(shí)候就學(xué)過(guò)。
該算法的好處呢,正如它開(kāi)始所說(shuō)的,Latency Hiding & Bandwidth Reduction,從原則上解決了網(wǎng)絡(luò)延遲導(dǎo)致的不同步的問(wèn)題,并且有效的減少了帶寬,不好的地方就是該算法基本上只能使用于移動(dòng)中的同步,當(dāng)然,移動(dòng) 的同步是網(wǎng)絡(luò)游戲中同步的最大的問(wèn)題。
該方法結(jié)合我在《網(wǎng)絡(luò)游戲的同步》一文中提出的綜合同步法的構(gòu)架可以基本上解決掉網(wǎng)絡(luò)游戲中走路同步的問(wèn)題。相關(guān)問(wèn)題歡迎大家一起討論。
有關(guān)導(dǎo)航推測(cè)算法(Dead Reckoning)中的平滑處理:
根據(jù)我上篇文章所介紹的,在節(jié)點(diǎn)A收到節(jié)點(diǎn)B新的PDU包時(shí),如果和A本地的關(guān)于B的模擬運(yùn)動(dòng)的坐標(biāo)不一致時(shí),怎么樣在A的屏幕上把B拽到新的 PDU包所描敘的點(diǎn)上面去呢,上文中只提了用“很平滑的移動(dòng)”把B“拉扯”過(guò)去,那么實(shí)際中應(yīng)該怎么操作呢?這里介紹四種方法。
第一種方法,我取名叫直接拉扯法,大家聽(tīng)名字也知道,就是直接把B硬生生的拽到新的PDU包所描敘的坐標(biāo)上去,該方法的好處是:簡(jiǎn)單。壞處是:看了以下三種方法之后你就不會(huì)用這種方法了。
第二種方法,叫直線(xiàn)行走(Linear),即讓B從它的當(dāng)前坐標(biāo)走直線(xiàn)到新的PDU包所描敘的坐標(biāo),行走速度用上文中所介紹的經(jīng)典算法:
目標(biāo)點(diǎn) = 原點(diǎn) + 速度 * 時(shí)間差 + 1/2 * 加速度 * 時(shí)間差算出:
首先算出從當(dāng)前坐標(biāo)到PDU包中描敘的坐標(biāo)所需要的時(shí)間:
T = Dest( TargetB – OriginB ) / Speed
然后根據(jù)新PDU包中所描敘的坐標(biāo)信息模擬計(jì)算出在時(shí)間T之后,按照新的PDU包中的運(yùn)動(dòng)信息所應(yīng)該達(dá)到的位置:
_TargetB = NewPDU.Speed * T
然后根據(jù)當(dāng)前模擬行動(dòng)中的B和_TargetB的距離配合時(shí)間T算出一個(gè)修正過(guò)的速度_S:
_S = Dest( _TargetB – OriginB ) / T
然后在畫(huà)面上讓B以速度_S走直線(xiàn)到Target_B,并且在走到之后調(diào)整其速度,方向,加速度等信息為新的PDU包中所描敘的。
這種方法呢,非常的土,會(huì)讓物體在畫(huà)面上移動(dòng)起來(lái)變得非常的不現(xiàn)實(shí),經(jīng)常會(huì)出現(xiàn)很生硬的拐角,而且對(duì)于經(jīng)常要修改的速度_S,在玩家A的畫(huà)面上,玩家B的行動(dòng)會(huì)變得非常的詭異。其好處是:比第一種方法要好。
第三種方法,叫二次方程行走(Quadratic),該方法的原理呢,就是在直線(xiàn)行走的過(guò)程中,加入二次方程來(lái)計(jì)算一條曲線(xiàn)路徑,讓Dest( _TargetB – OriginB )的過(guò)程是一條曲線(xiàn),而不是一條直線(xiàn),恩,具體的實(shí)現(xiàn)方法,就是在Linear方法的計(jì)算中,設(shè)定一個(gè)二次方程,在Dest函數(shù)計(jì)算距離的時(shí)候根據(jù)設(shè)定的 二次方程來(lái)計(jì)算,這樣一來(lái),可以使B在玩家A屏幕上的移動(dòng)變得比較的有人性化一些。但是該方法的考慮也是不周全的,僅僅只考慮了TargetB到 _TargetB的方向,而沒(méi)有考慮新的PDU包中的方向描敘,那么從_TargetB開(kāi)始模擬行走的時(shí)候,仍然是會(huì)出現(xiàn)比較生硬的拐角,那么下面提出的 最終解決方案,將徹底解決這個(gè)問(wèn)題。
——————————————————————————————————————————
網(wǎng)絡(luò)游戲同步詳解之三
最后一種方法叫:立方體抖動(dòng)(Cubic Splines),這個(gè)東東比較復(fù)雜,它需要四個(gè)坐標(biāo)信息作為它的參數(shù)來(lái)進(jìn)行運(yùn)算,第一個(gè)參數(shù)Pos1是OriginB,第二個(gè)參數(shù)Pos2是 OriginB在模擬運(yùn)行一秒以后的位置,第三個(gè)參數(shù)Pos3是到達(dá)_TargetB前一秒的位置,第四個(gè)參數(shù)pos4是_TargetB的位置。
Struct pos {
Coordinate X;
Coordinate Y;
}
Pos1 = OriginB
Pos2 = OriginB + V
Pos3 = _TargetB – V
Pos4 = _TargetB
運(yùn)動(dòng)軌跡中(x, y)的坐標(biāo)。
x = At^3 + Bt^2 + Ct + D
y = Et^3 + Ft^2 + Gt + H
(其中時(shí)間t的取值范圍為0-1,在Pos1的時(shí)候?yàn)?,在Pos4的時(shí)候?yàn)?)
x(0-3)代表Pos1-Pos4中x的值,y(0-3)代表Pos1-Pos4中y的值
A = x3 – 3 * x2 +3 * x1 – x0
B = 3 * x2 – 6 * x1 + 3 * x0
C = 3 * x1 – 3 * x0
D = x0
E = y3 – 3 * y2 +3 * y1 – y0
F = 3 * y2 – 6 * y1 + 3 * y0
G = 3 * y1 – 3 * y0
H = y0
上面是公式,那么下面我們來(lái)看看如何獲得Pos1-Pos4:首先,Pos1和 Pos2的取值會(huì)比較容易獲得,根據(jù)OriginB配合當(dāng)前的速度和方向可以獲得,然而Pos3和Pos4呢,怎么獲得呢?如果在從Pos1到Pos4的 過(guò)程中有新的PDU到達(dá),那么我們定義它為NewPackage。
Pos3 = NewPackage.X + NewPackage.Y * t + 1/2 * NewPackage.a * t^2
Pos4 = Pos3 – (NewPackage.V + NewPackage.a * t)
如果沒(méi)有NewPackage的情況下,則Pos3和Pos4按照開(kāi)始所規(guī)定的方法獲得。
至此,關(guān)于導(dǎo)航推測(cè)的算法大致介紹完畢。
原文來(lái)自:http://xinsync.xju.edu.cn/index.php/archives/4079
posted on 2009-09-10 19:21
暗夜教父 閱讀(372)
評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi):
Game Development