1. 程式人生 > >每個程式設計師都需要知道一些遊戲網路知識

每個程式設計師都需要知道一些遊戲網路知識

作為一個程式設計師,你有沒有想象過多人遊戲是如何實現的?

在外行人看來遊戲很神奇:兩個或者更多的玩家在網路上分享共同的經歷,就像他們真實的存在於相同的虛擬的世界一樣。遊戲看起來猶如一個巨大的魔術,奇妙而又刺激,但作為一個開發人員我們知道,真實的情況和我們所看到的並不一樣,那只是一種錯覺。你感受到的共享現實,實際上是在那個時刻內,由你自己的獨特視角和位置所感知的近似情況。

Peer-to-Peer 幀同步

最初的遊戲是通過peer-to-peer來聯網的,每個計算機通過網狀拓撲的結構的彼此連線並交換資訊。你仍然可以看到這種模型存在於RTS遊戲中,而且基於某些原因它還很有趣,也許是因為它是大多數人認為遊戲網路工作方式的第一種方式。

處理遊戲資訊的基本思想就是把遊戲的資料抽象並轉換成一系列命令訊息,當處理每個轉換的時候就直接演變為遊戲的狀態。比如:移動單位、攻擊物體、建造建築。這一切都需要線上的每個玩家機器,從一個初始化命令開始之後,都執行完全相同的命令和轉換資料。

這些看起來是如此簡單和優雅,但不幸的它們有幾個因素限制者我們。

第一個限制,要保證遊戲狀態完全確定一致的是異常困難,特別是保持每臺機器上每個轉換輸出都保持相同。比如,一個單位在兩臺機器上有略微不同的路徑,在一臺機器上早一些到達並開始了戰鬥,結果反敗為勝,而在另一臺機器上,由於稍微晚一些到達而失敗。就像一隻蝴蝶扇動了翅膀,然後在世界的另一邊導致了颶風的出現,隨著時間的推移,一個微小的區別就會導致兩邊完全的不同步。

第二個限制,為了保證遊戲的所有玩家輸出一致,這就需要等到所有玩家的當前回合數據都到達之後才可以模擬播放這一回合動作。這就意味著遊戲中的每一個玩家都需要等待網路延遲最高的那個玩家。RTS遊戲通常代表性地通過立即提供音訊反饋與(或是)播放吟唱(過渡)動畫來掩蓋這段延遲,但是最終真正影響遊戲的動作要在這段延遲過去之後才能進行。

第三個限制,因為遊戲中狀態改變的同步是通過傳送命令資訊來同步的。所以為了遊戲中玩家狀態都一致,需要所有的玩家都要從相同的初始狀態來開始遊戲。這意味著每個玩家必須在開始遊戲之前先加入房間然後一起開始遊戲,儘管理論上也可以支援讓某些玩家晚些加入遊戲,但是在一場進行中的遊戲中獲得一個完全確定的起始點的難度相當大,所以這種情況並不常見。

儘管有這些因素限制困擾者我們,不過這個模型還是很適合RTS遊戲的,並且它仍然存在於今天的遊戲當中,例如“Command and Conquer”、“Age of Empires”與“Starcraft”等。原因就是在RTS遊戲中,裡面包含了上千多的單位,這些單位都有自己的狀態需要同步,而且他們資料量都太大了,很難用來在玩家之間交換。別無選擇,我們只能通過這些遊戲狀態改變的命令來同步。

所以以上這些就是 peer-to-peer 幀同步的網路遊戲模型的介紹了,對於其他型別的遊戲,最先進的技術已經開始出現了。讓我們現在從DoomQuake 以及 Unreal經典遊戲中開始一起觀察動作遊戲的技術演化。

客戶端/伺服器(c/s架構)

在動作遊戲的時代,以上幀同步的限制在Doom 遊戲中變得更加明顯,儘管在區域網中體驗還不錯,但在對於網際網路的使用者來說它體驗太糟糕了:

儘管可以使用一個貓(調變解調器)把兩個Doom 機器通過網際網路連線在一起,但他們一起遊戲會異常緩慢。範圍從無法遊戲(例如:14.4Kbps PPP 連線)到稍微可以玩(例如 :28.8Kbps 貓執行一個被SLIP驅動壓縮的資料)之間遊戲聯機都異常緩慢。由於這些連線方式只是邊際效用,本文將僅關注直接的網路連線。

這個問題是因為Doom網路部分本來就是隻為區域網而設計的,並且使用了前面介紹的peer-to-peer 幀同步模型。每一回合每個玩家的輸入的資訊(比如關鍵按鍵等)都與其他人進行同步通知,並且任何玩家在播放這一幀動畫之前,必須得等到所有其他玩家的關鍵按鍵資訊都被接收到,才可以去模擬播放。

也就是說,在你可以轉身(轉換),移動或者射擊之前,你必須等待延遲最大的貓(調製調解器)玩家的輸入。只是想想上述那個人所寫的“這些連線方式只是邊際效用”就會讓人咬牙切齒和沮喪了。

為了改變這種現狀,只能在區域網以及大學網路和大型企業才能獲得良好連線而進行遊戲,是需要改變這種網路模型了。在1996年,這變成了現實並被實現了,John Carmack當時 釋出雷神之錘,他採用客戶端/伺服器(C/S)架構代替了P2P模型。

如今遊戲中的玩家可以不必再執行相同的程式碼以及直接相互通訊,每個玩家的機器是都是一個“客戶端”,他們都通過一臺叫做“伺服器”的機器進行通訊互動。遊戲的最終狀態確定不再依賴於每臺客戶端機器來共同確認,而是由伺服器來確定最終結果。每個客戶端如同一個啞終端,用來展示一個近似值的表演,真是的遊戲狀態是運行於伺服器之上。

在一個純粹的c/s架構中,你不必在本地運行遊戲程式碼,而是把一些例如按鍵、滑鼠移動,點選等輸入資訊傳送到伺服器。伺服器會在遊戲世界中更新你的玩家狀態,然後再封包一個包含你角色資訊以及臨近玩家資料的包回覆給你的客戶端。所有的客戶端在每個訊息更新的間隙做一個插值預測,以改善在每個狀態更新期間,物體可以平滑的移動,如此,你就有一個可以聯網的客戶端/伺服器架構的遊戲了。

這已經是向前邁出了極大的一步。遊戲的體驗依賴於客戶端和伺服器的連線,而不是遊戲中延遲最大的那個玩家。如此可以支援玩家在遊戲中自由的進入和退出,同時由於客戶端/伺服器降低了平均每位玩家的頻寬,從而可以增加更多的線上玩家。

但是這裡仍然有一些問題存在於 c/s 架構中:

我記得我交代了所有從DOO到Quake中關於網路的決策,但是重要的是我正在使用錯誤的假設來做一個好的網路遊戲。我原先設計的目標是網路延遲<200ms。人們通過一個好的網路供應商連線網際網路,從而可以獲得一個好的遊戲體驗。但事與願違,世界上99%的使用者使用貓(調製調解器)通過 slip或者ppp 進行連線,而他們常常都會通過槽糕而又擁擠的ISP。這會帶來最低300+ms 的 網路延遲。一個訊息要經過,客戶端>使用者貓>ISP貓>伺服器>ISP貓>使用者貓>客戶端。上帝,這太遜了。

OK,我做了一個錯誤的設定。我在家裡使用T1 寬頻,所以我只是不瞭解在PPP網路下的生活。我現在就解決它。

這個問題當然是延遲。

接下來John在他釋出QuakeWorld的時候將改變這個行業。

客戶端預測(Client-Side Prediction

在原來的Quake遊戲中,你會感覺到電腦與伺服器之間的延遲。比如,你按鍵向前移動,在你真正移動之前,你需要等到資料包傳送伺服器然後再回復到你的客戶端,你才可以真正的移動。按鍵開火,在你的射擊之前同樣需要相同的等待。

如果你玩過任何FPS遊戲,比如:Modern Warfar,你會發現並沒有延遲發生。那麼fps遊戲是如何做到在多人情況下,你的動作看起來並沒有延遲?

這個問題被分為兩個部分來解決。第一個部分是客戶端移動預測,這事John Carmack 為 QuakeWorld遊戲多開發的,後來被合併到了Tim Sweeney的虛幻網路模組。第二個部分就是延遲補償,它是有Valve公司的Yahn Bernier在Counterstrike所開發。那麼在這個章節,我們把焦點放在第一部分——隱藏使用者移動的延遲。

當寫到關於他即將釋出的QuakeWorld計劃的時候,John Carmack 講到:

我現在允許客戶端可以預測使用者的移動,直到伺服器的權威資訊回覆之前。這是一個重大的結構變更。客戶端需要知道關於物件的硬度、摩擦力、重力等一系列基礎屬性。我很傷心的看到,客戶端僅作為一個終端存在將會離開,但作為一個實用主義者,我必須超越這種理想情懷。

那麼現在我們為了消除延遲,客戶端需要執行更多的程式碼。它現在不再是一個只把輸入傳送給伺服器然後再把返回資訊進行插入的啞終端。現在客戶端的機器可以執行一部分遊戲程式碼,它可以在本地預測你的角色移動並且可以即時響應你的輸入。

現在當你即刻按鍵向前,你的遊戲會立刻向前移動,不會再去等待資料往返一次客戶端和伺服器之間才來迴應你的操作。

這種方式的難點不在於預測,這種預測工作,就像正常的遊戲程式碼一樣 —— 根據玩家的輸入,及時地更新遊戲角色的狀態。而難點在於,當客戶端和伺服器對於玩家角色所做的事情(動作)核檢不一致的時候,客戶端如何基於伺服器資訊進行更正。

現在你會想,hey,如果程式碼執行在客戶端——為何不以客戶端的資訊為準?客戶端可以自己的為角色模擬執行程式碼,並且只需要在每次傳送資料包時告知伺服器這些資訊。如果每個客戶端都對伺服器傳送相同的資訊,告訴伺服器“這是我現在的位置資訊”,那麼將會帶來這樣的問題。客戶端會很容易被黑客攻擊並控制,這樣在RPG遊戲中,一個作弊便可以立即躲避對方技能擊中,或者當你射擊的時候瞬間移動到你的身後。

所以在FPS遊戲中,儘快每個玩家的客戶端可以預測他們自己的角色進行操作移動,但最終每個玩家的角色狀態絕對以伺服器為準。就像Tim Sweeney 在所寫的文章The Unreal Networking Architecture中描述的一樣:“伺服器才是主人”。

這就是有趣的地方。如果客戶端和伺服器產生了不一致,客戶端必須基於伺服器的資訊為準並更新,但是由於客戶端和伺服器之前有延遲,伺服器的修正必然是過去的動作。比如,如果資訊從客戶端到伺服器耗時100ms,然後返回又耗時100ms,那麼任何伺服器的的修正都是客戶端200ms之前的行為動作,這個時間正好是客戶端預測角色移動的時間。

如果客戶端每個動作都會被伺服器修正,那麼你將會看客戶端被拉回了原先的位置,如此客戶端將做不了任何預先預測的運算。那麼我們如何解決這個問題,依然可以保持客戶端提前預測?

解決方案就是在客戶端建立一個buffer,然後用來迴圈保持角色的狀態以及本來玩家的輸入。當客戶端收到了伺服器的更正資訊時候,它首先丟棄掉buffer裡面比(伺服器回覆的)更正狀態要老的狀態資訊,然後基於(更正的)正確的狀態重放儲存在buffer裡面的輸入資訊,重發的這些輸入資訊的範圍是從正確狀態到當前預測時間之間。如此實際上,客戶端只是看似無形中“倒帶和重放”當地玩家角色運動的最後n幀,同時保持世界其他地方沒有變化。

這種方法可以讓玩家感覺在控制遊戲的時候沒有延遲,同時也改善了客戶端和伺服器之間程式碼執行的一致性——在同等輸入的情況下保持一致的結果。當然了,修正的情況很少發生,Tim Sweeney 如此描述:

…對於客戶端和伺服器最好的是:所有情況下,伺服器都是權威的。幾乎所有的時間,客戶端模擬的和伺服器的資料都是一致,所以客戶端的位置很少被修正。只有的少數罕見的情況下,例如一個玩家被火箭擊中,或者和一個敵人(怪物)碰撞上,那麼客戶端本地的情況有可能需要被修正。

也就是說,只有當玩家的角色被一些外部事件影響玩家的輸入,並且這些不能被客戶端預測時,玩家的位置(行為)需要被伺服器修正。當然,如果玩家試圖作弊,必然會被伺服器修正。

相關推薦

每個程式設計師需要知道一些遊戲網路知識

作為一個程式設計師,你有沒有想象過多人遊戲是如何實現的? 在外行人看來遊戲很神奇:兩個或者更多的玩家在網路上分享共同的經歷,就像他們真實的存在於相同的虛擬的世界一樣。遊戲看起來猶如一個巨大的魔術,奇妙而又刺激,但作為一個開發人員我們知道,真實的情況和我們所看到的並不一樣,那

小黃鴨除錯法,每個程式設計師知道

花了一下午(或一天)在試圖解決某個 Bug,後來才知道解決方案很簡單,當時就是沒有想到。 有個同事正好路過,看到你愁眉苦臉的,問你“怎麼了呀?” “噢,是這樣的。我遇到了一個問題,點選這個控制元件的時……” 當你正準備和同事詳細解釋的時候,突然靈光一現,你話都沒說完

每個程式設計師應該知道的 15 個最佳 PHP 庫

1. PChart PChart是一個令人印象深刻的PHP庫,可以以一種視覺化圖表的形式生成文字資料。資料可以展示為柱狀圖,餅狀圖,以及其他格式。使用SQL查詢可以幫助PHP指令碼建立令人驚歎的圖表和圖形。 2. PHP CAPTCHA PHP CAPTCHA是另一個偉

每個程式設計師知道的 5 個定律

定律-或稱法則,可以指導我們並讓我們在同伴的錯誤中學習。這篇文章中,我將介紹我每次設計或實現軟體時出現在我腦海的五大定律。其中有些和開發有關,有些和系統組織有關。它們可以幫助你成為合格的軟體工程師。 墨菲定律 “凡是可能出錯,就一定出錯。” 這條定律來源於 Edward Murphy —— 一名

每個程式設計師應該知道的8個Linux命令

cat     cat – 連線檔案,並輸出結果 sort     sort – 檔案裡的文字按行排序 grep     grep, egrep, fgrep – 打印出匹配條件的文字行 cut     cut – 刪除檔案中字元行上的某些區域 sed     se

linux 每個程式設計師應該知道的8個Linux命令

每個程式設計師,在職業生涯的某個時刻,總會發現自己需要知道一些Linux方面的知識。我並不是說你應該成為一個Linux專家,我的意思是,當面對linux命令列任務時,你應該能很熟練的完成。事實上,學會了下面8個命令,我基本上能完成任何需要完成的任務。 注意:下

每個程式設計師應該知道

http://projectmona.com/bits-of-brilliance-session-five/ 裡面內容很雜但很豐富,是UIUC教授Jeff Erickson在程式設計方面的個人收集(其他收集可以參見:http://projectmona.com/bits-

(不斷更新)每個程式設計師應該知道的那些事兒

http://projectmona.com/bits-of-brilliance-session-five/裡面內容很雜但很豐富,是UIUC教授Jeff Erickson在程式設計方面的個人收集(其他收集可以參見:http://projectmona.com/bits-of

每個Java程式設計師應該知道的5個JVM命令列標誌

JVM是多數開發人員視為理所當然的Java功能和效能背後的重負荷機器。然而,我們很少有人能理解JVM是如何進行工作的—像任務分配和垃圾收集、轉動執行緒、開啟和關閉檔案、中斷和/或JIT編譯Java位元組碼,等等。 不熟悉JVM將不僅會影響應用程式效能,而且當J

每個程式設計師應當瞭解的11句話

1.技術只是解決問題的選擇,而不是解決問題的根本 我們可以因為掌握了最新的JavaScript框架ahem、Angular的IoC容器技術或者某些程式語言甚至作業系統而歡欣雀躍,但是這些東西並不是作為程式設計師的我們用來解決問題的根本——它們只是用於幫助我們解決問題的簡單工具。 我們必須非常謹慎

SQL效能優化十條經驗,後臺程式設計師需要掌握

1.查詢的模糊匹配儘量避免在一個複雜查詢裡面使用 LIKE '%parm1%'—— 紅色標識位置的百分號會導致相關列的索引無法使用,最好不要用.解決辦法:其實只需要對該指令碼略做改進,查詢速度便會提高近百倍。改進方法如下:a、修改前臺程式——把查詢條件的供應商名稱一欄由原來的文字輸入改為下拉列表,使用者模糊輸

[轉]國外程式設計師推薦:每個程式設計師應該讀的非程式設計書

五年前有網友在 Stackoverflow 發帖提問:『程式設計師應該讀哪些非程式設計方面的書?』。有很多程式設計師響應,他們在推薦的同時也寫下了自己的評語。本文摘編其中 29 本書,下面就按照各書的推薦數排列。另外,本月初我們在伯樂頭條也發起了相同的討論帖《你最喜歡的非程式設計書是哪一本?》,已有很多的朋友

程式猿養生方法(每個程式設計師應該看一看)

前言 程式設計師職業生涯中,健康問題尤為突出。隨著時間的流逝,夢想可能漸漸暗淡,激情可能慢慢消退,但是,有一點卻很肯定,我們的身體大不如前,視力下降,慢性腸胃炎,頸椎病,失眠,神經衰弱,此類慢性疾病接踵而來。 身體是自己的,也是一輩子的事情,人的自我恢復能力並不是很強;所以我向來不建議為了事業,而犧牲身體。

成為一名優秀程式設計師需要知道的15件事

1. 懂得分享。儘可能使用開源,並且當你有能力的時候,要對其有所貢獻。聚全社會之智慧,勝過某些“大”公司之短視。   2. 公平競爭。嘗試其他技術、框架、方法和觀點。不要總以為只有你的選擇才是可行的。別的選擇也有可能比你的要強得多。要以開放的心態,來檢驗其他人的選擇。  

學習C語言的教材、如何成為一名優秀的C程式設計師、激發程式設計師創意的6本書、國外程式設計師推薦:每個程式設計師應讀的書

學習C語言的教材 我的C語言是自學的,這些年看過不少教材。 下面,我對其中一些教材做個點評。 1. How to Think Like a Computer Scientist: C version 這是我讀過最易懂的C語言教材。 雖然它只講

使用Mono平臺前,請牢記產品觀點(所有.Net程式設計師建議知道的)

體驗一種維度 有一種喜歡叫做無法抵擋,有一種幸福叫做行走於路上;有一種誤解叫做IT,有一種美叫做由裡及外,有一種體貼叫做真心服務;有一種夢想是做點事情。有一種奢侈,落地窗前情人伴,讀書一日,日月變而不驚人。

國外程式設計師推薦:每個程式設計師應該讀的非程式設計書

【伯樂線上導讀】:五年前有網友在 Stackoverflow 發帖提問:『程式設計師應該讀哪些非程式設計方面的書?』。有很多程式設計師響應,他們在推薦的同時也寫下了自己的評語。本文摘編其中 29 本書,下面就按照各書的推薦數排列。另外,本月初我們在伯樂頭條也發起了相

國外程式設計師推薦:每個程式設計師應讀的書

【更新】:近日(2012年8月17日)重看 StackOverflow 的原討論帖,發現於今年年初被關閉了。不過有人做了彙總,把其他回覆中提到的書籍,放在投票數最高的回覆中。新更新新增 59 本書,詳情可見文章後半部分。 編者按:2008年8月4日,StackOve

每個程式設計師應該具備的除錯能力。

首先,除錯是⼀個程式設計師最基本的技能,其重要性甚⾄超過學習⼀門語⾔。不會除錯的程式設計師就意味著他即使會⼀門語⾔,卻不能編制出任何好的軟體。 VC/VS除錯快捷鍵: F9 //設定斷點和取消斷點 F10 //開始除錯//單步執⾏ F11 //進⼊

每一個做JAVA開發的程式設計師應該知道的JAVA發展史

作為一名Java語言的學習者,對Java的起源和發展有個大概的瞭解應是必要的。 小編給大家講個有趣的小故事,JAVA名字的來源,有兩種版本,其中一種可信度雖然不高,但仍有人聲稱是開發人員名字的組合:JamesGosling(詹姆斯·高斯林)ArthurVanHoff(阿瑟·凡·霍夫)AndyBech