我們一開始的游戲邏輯層是基于網(wǎng)絡(luò)包驅(qū)動(dòng)的,也就是將 client 消息定義好結(jié)構(gòu)打包發(fā)送出去,然后再 server 解析這些數(shù)據(jù)包,做相應(yīng)的處理。
寫了一段時(shí)間后,覺得這種方案雜亂不利于復(fù)雜的項(xiàng)目。跟同事商量以后,改成了非阻塞的 RPC 模式。
首先由處理邏輯的 server 調(diào)用 client 的遠(yuǎn)程方法在 client 創(chuàng)建出只用于顯示表現(xiàn)的影子對(duì)象;然后 server 對(duì)邏輯對(duì)象的需要client 做出相應(yīng)表現(xiàn)的操作,變成調(diào)用 client 端影子對(duì)象的遠(yuǎn)程方法來實(shí)現(xiàn)。
這使得游戲邏輯編寫變的清晰了很多,基本可以無視網(wǎng)絡(luò)層的存在,和單機(jī)游戲的編寫一樣簡單。
本質(zhì)上,這樣一個(gè)系統(tǒng)跟網(wǎng)絡(luò)包驅(qū)動(dòng)的方式?jīng)]有區(qū)別;但是從編碼表現(xiàn)形式上要自然很多。正如 C 語言也可以實(shí)現(xiàn)面向?qū)ο螅珔s沒有 C++ 實(shí)現(xiàn)的自然一樣。在這個(gè)系統(tǒng)中,引擎封裝了對(duì)象管理的部分,使得邏輯編寫的時(shí)候不再需要處理討厭的對(duì)象數(shù)字 id ;還隱藏了消息發(fā)送或廣播的問題。
我把玩家控制的角色,和服務(wù)器上你的角色分做兩個(gè)東西。即,你控制的你,和服務(wù)器認(rèn)為的你就分開了。服務(wù)器認(rèn)為的你,你看見的服務(wù)器上的其他人是一類東西。操作自己的角色行動(dòng)時(shí),你通過 client 上的控制器的遠(yuǎn)程方法向服務(wù)器發(fā)送指令;而服務(wù)器通過遠(yuǎn)程調(diào)用每個(gè)角色的遠(yuǎn)程方法讓 client 可以收到感興趣的所有角色的行為。
這樣,client 永遠(yuǎn)都是通過一個(gè)控制器調(diào)用其遠(yuǎn)程方法來告訴服務(wù)器"我要干什么",而服務(wù)器的邏輯層則通過調(diào)用其上所有邏輯對(duì)象的遠(yuǎn)程方法來改變每個(gè)對(duì)象的狀態(tài)。而引擎就根據(jù)每個(gè)鏈接的需要,廣播這些消息,使得每個(gè) client 上對(duì)應(yīng)的影子對(duì)象可以收到狀態(tài)改變的消息。
這些,就是半個(gè)月來我跟同事一起做的工作。當(dāng)然,由于我們用腳本編寫邏輯層,這樣,腳本接口可以比 C 接口實(shí)現(xiàn)的漂亮的多。
首先是自定義格式的接口描述文件,用自編寫的工具自動(dòng)編譯成對(duì)應(yīng)腳本代碼。我們只需要在腳本中編寫對(duì)應(yīng)的類,就可以自動(dòng)響應(yīng)遠(yuǎn)端調(diào)用的方法了。而調(diào)用遠(yuǎn)程方法,也跟本地方法保持同樣的形式,寫起來跟本地函數(shù)調(diào)用沒有區(qū)別。這在以前用 C/C++ 編寫邏輯的時(shí)候是很難做到的。
其次,引擎內(nèi)部做好對(duì)象的管理工作,負(fù)責(zé)把通訊協(xié)議上的 id 轉(zhuǎn)換成邏輯層中的對(duì)象傳遞給邏輯層使用。
再次,enum 這樣的類型再也不需要用一些數(shù)字的常數(shù)了,也不需要在腳本額外的定義出來。可以在接口文件中定義好,經(jīng)過引擎的處理后,邏輯層可以直接用更為友好的字符串代替,而不失去效率。
編寫邏輯的程序員不再需要關(guān)心網(wǎng)絡(luò)的問題后,就可以把心思放在細(xì)節(jié)上。
最后,對(duì)于實(shí)現(xiàn)行為預(yù)測來補(bǔ)償網(wǎng)絡(luò)延遲的特性上。在先前的版本中,我們?yōu)榱藢?shí)現(xiàn)這個(gè),花了不少的氣力。主要是將時(shí)間戳信息放在基礎(chǔ)通訊協(xié)議中來輔助實(shí)現(xiàn)。具體的消息包收到后,再計(jì)算延遲時(shí)間來推算當(dāng)前的狀態(tài)。現(xiàn)在,可以把時(shí)間信息封裝到 RPC 中,讓每個(gè)遠(yuǎn)程方法自動(dòng)帶有延遲時(shí)間,方便計(jì)算。按模擬程序的實(shí)際效果上看,單單位置同步的預(yù)測策略,可以讓延遲在 8 秒之內(nèi)的玩家可以忍受;而延遲小于 1 秒的時(shí)候,幾乎不會(huì)受到滯后的影響了。
關(guān)于每個(gè)鏈接感興趣的信息的問題,決定了每個(gè)邏輯對(duì)象的狀態(tài)改變要通知哪些人。目前的想法是獨(dú)立到單獨(dú)進(jìn)程去處理,我們?cè)谔幚磉B接的服務(wù)器和處理邏輯的服務(wù)器之間設(shè)置單獨(dú)的服務(wù)器來管理每個(gè)鏈接感興趣的對(duì)象,這個(gè)任務(wù)相對(duì)單一且責(zé)任重大,獨(dú)立出來可以大大減輕邏輯服務(wù)器的復(fù)雜度。
posted on 2009-09-09 10:42
暗夜教父 閱讀(868)
評(píng)論(1) 編輯 收藏 引用 所屬分類:
Game Development