邏輯服務(wù)器的設(shè)計(jì):
邏輯服務(wù)器的設(shè)計(jì)思路其實(shí)很簡(jiǎn)單,我們把游戲里的對(duì)象分為2大類,城市和人。所有的游戲邏輯操作都是圍繞這這兩個(gè)對(duì)象進(jìn)行的。其中城市對(duì)象又還可以細(xì)分為多個(gè)子對(duì)象,這些對(duì)象在結(jié)構(gòu)上是屬于城市的,它們分別是碼頭、船廠、交易所、銀行、酒館。
在游戲進(jìn)行的時(shí)候,玩家要進(jìn)行某些操作的時(shí)候(購(gòu)買(mǎi)貨物)會(huì)向服務(wù)器端發(fā)送游戲消息,這時(shí)候,服務(wù)器在收到消息后,會(huì)通過(guò)消息玩家的ID知道玩家當(dāng)前在那個(gè)城市里,然后再由這個(gè)城市對(duì)象去處理這條游戲消息。在城市對(duì)象收到游戲消息后,首先是對(duì)一級(jí)分類進(jìn)行判斷,這個(gè)級(jí)別的分類標(biāo)準(zhǔn)是邏輯上的分類,這點(diǎn)在前面已經(jīng)說(shuō)過(guò)了。這時(shí)候如果消息的邏輯分類是交易所,城市對(duì)象,會(huì)再調(diào)用城市對(duì)象里面的交易所對(duì)象去執(zhí)行該條游戲消息,這時(shí)候,城市對(duì)象就要根據(jù)消息的二級(jí)分類來(lái)判斷玩家到底是要做什么事情了。這時(shí)候,如果消息是BuyReq 者說(shuō)明玩家是打算購(gòu)買(mǎi)一類貨物,交易所對(duì)象,再?gòu)南⒗锔綆У慕Y(jié)構(gòu)體變量讀出要購(gòu)買(mǎi)貨物的編號(hào)和數(shù)量。這時(shí)候交易所首先要判斷,這類貨物在本交易所里時(shí)候存在,并且能夠賣(mài),如果可以,再調(diào)用用戶對(duì)象的購(gòu)買(mǎi)貨物函數(shù),由用戶對(duì)象進(jìn)行下一步的處理(看看時(shí)候有足夠的錢(qián),玩家的船是否還能裝得下這個(gè)貨物等等..)如果可以,則由用戶類返回成功,否則,返回錯(cuò)誤的信息。在交易所收到用戶類返回的信息后,再根據(jù)返回的結(jié)果,生成相應(yīng)的游戲消息發(fā)還給用戶。
整個(gè)過(guò)程很簡(jiǎn)單,所以,在項(xiàng)目開(kāi)始的時(shí)候,我就先那這個(gè)系統(tǒng)開(kāi)刀,在分配項(xiàng)目任務(wù)的時(shí)候,我也就有限考慮自己做簡(jiǎn)單的東西,然后把復(fù)雜的地圖服務(wù)器仍給了另外一位同學(xué)^_^。不過(guò)雖然這個(gè)模塊簡(jiǎn)單,不過(guò)涉及到的東西很多,難度雖然不大,但是很煩瑣,一個(gè)小小的問(wèn)題就可能造成今后游戲存在的嚴(yán)重bug,所以在進(jìn)行沒(méi)有邏輯事件的處理都是時(shí)候,我都是很小心的在做,剛開(kāi)始的時(shí)候,還寫(xiě)過(guò)一定的測(cè)試用例去測(cè)試系統(tǒng),不過(guò)現(xiàn)在看來(lái),當(dāng)時(shí)寫(xiě)的測(cè)試用例存在有一定的問(wèn)題:
1。是在完成代碼后才寫(xiě)測(cè)試,XP方法要求測(cè)試用例要優(yōu)先與代碼的編寫(xiě)。
2。只寫(xiě)了測(cè)試過(guò)程,沒(méi)有編寫(xiě)自動(dòng)化的結(jié)果判斷。有測(cè)試,就必須要有預(yù)期的測(cè)試結(jié)果,當(dāng)時(shí)寫(xiě)的測(cè)試用例大多只是看看那個(gè)函數(shù)能夠正確運(yùn)行而已,所有結(jié)果都是直接輸出到屏幕上,讓我自己來(lái)判斷,在測(cè)試用例寫(xiě)過(guò)一段時(shí)間后,要測(cè)試的部分太多,有些看不過(guò)來(lái)了,所以寫(xiě)了測(cè)試輸入,一定要想好輸出結(jié)果,并且要讓測(cè)試代碼自己把函數(shù)返回結(jié)果與想好的輸出對(duì)結(jié)果進(jìn)行判斷,從而減少人工判斷的錯(cuò)誤性。
3。測(cè)試用例過(guò)少,因?yàn)闀r(shí)間的關(guān)系,只是在前面的階段寫(xiě)過(guò)一定的測(cè)試用例,到后來(lái)進(jìn)度緊張后,就沒(méi)空去進(jìn)行測(cè)試了。歸結(jié)起來(lái),應(yīng)該是沒(méi)有一個(gè)良好的測(cè)試框架與測(cè)試機(jī)制,有好的框架,可以減少測(cè)試用例的編寫(xiě)時(shí)間,從而有更多的時(shí)間去編寫(xiě)代碼。同時(shí)因?yàn)轫?xiàng)目不是什么正規(guī)的項(xiàng)目,所以對(duì)測(cè)試的要求也不是太嚴(yán)格。
除了測(cè)試存在不足外,程序的整個(gè)結(jié)構(gòu)上也存在著嚴(yán)重的不足:
1。當(dāng)初因?yàn)榭紤]得簡(jiǎn)單,每個(gè)玩家的游戲消息都會(huì)有一個(gè)與它相對(duì)應(yīng)的游戲消息,所以,我在程序里大膽的采用了函數(shù)返回游戲消息指針的方式,在系統(tǒng)完成游戲消息處理后,產(chǎn)生一條游戲消息,并且把改游戲消息以返回消息內(nèi)存首地址指針的方式返回給調(diào)用處理的函數(shù)。這樣一層層的返回,一直返回到socket的OnRead()函數(shù),然后再在這個(gè)函數(shù)里send數(shù)據(jù)給客戶端。這樣的設(shè)計(jì)在剛開(kāi)始的時(shí)候,并沒(méi)有覺(jué)得什么不托,但是實(shí)際到后期才發(fā)覺(jué),這樣的設(shè)計(jì)有一個(gè)很大的不方便,有些從客戶端來(lái)的游戲消息,它的返回消息可能不只一個(gè),所以在一個(gè)函數(shù)的返回值里就不太好處理了。這個(gè)問(wèn)題我開(kāi)始的時(shí)候沒(méi)有太注意,因?yàn)楹芏嘞⒍贾皇怯幸粭l返回消息而已,哪知到后來(lái)系統(tǒng)的擴(kuò)展,很多函數(shù)處理都要返回多條數(shù)據(jù),所以,在后來(lái)的不得不在邏輯處理里面增加消息發(fā)送函數(shù)。不過(guò)這樣給我的感覺(jué)就不是很舒服了,邏輯處理里面就不應(yīng)該存在其它的東西,現(xiàn)在增加的消息的發(fā)送,就不是很好了。不過(guò)一直到現(xiàn)在,我都沒(méi)有找到合適的結(jié)局方法,所以,如果在一開(kāi)始的時(shí)候先想好消息該怎么發(fā)送,就不會(huì)存在這樣的混亂了。
2。在前面的代碼里,遺漏有創(chuàng)建游戲消息的代碼(交易所),后來(lái)感覺(jué)不爽,因?yàn)橐獎(jiǎng)?chuàng)建的東西很多,而且很多都是重復(fù)的,所以就用一個(gè)模版來(lái)處理創(chuàng)建過(guò)程。再到了后來(lái),覺(jué)得邏輯代碼里存在很多游戲邏輯消息的變量賦值過(guò)程,這樣的代碼也不是很好看,所以有進(jìn)一步把這個(gè)東西獨(dú)立出來(lái)做個(gè)函數(shù),這樣邏輯處理代碼就好看很多了。這個(gè)過(guò)程是一個(gè)不斷的發(fā)展過(guò)程,也都是看到不足后才進(jìn)行處理,所以,如果當(dāng)初就和上面的游戲數(shù)據(jù)發(fā)送一起考慮好,就不會(huì)留下很多垃圾代碼(這些代碼我現(xiàn)在還沒(méi)有處理掉)。
地圖服務(wù)器的設(shè)計(jì):
對(duì)于地圖服務(wù)器的設(shè)計(jì),在網(wǎng)上關(guān)于它的文章一直都比較多,說(shuō)得最多的就是如何實(shí)現(xiàn)讓客戶端與服務(wù)器進(jìn)行同步。所以,在項(xiàng)目開(kāi)始的時(shí)候,這個(gè)部分能夠參考的文章很多,不過(guò)也因?yàn)檫@個(gè)系統(tǒng)是交給一個(gè)完全沒(méi)有做過(guò)游戲的同學(xué)來(lái)制作,所以很多時(shí)候,很多概念性的東西需要理解,在理解的時(shí)候會(huì)造成一定的偏差,所以系統(tǒng)在實(shí)現(xiàn)的時(shí)候不是很完善。不過(guò)也因?yàn)檫M(jìn)行開(kāi)發(fā)的這位同學(xué)的實(shí)力不同一般,所以地圖服務(wù)器還是能夠運(yùn)行的,只不過(guò)^_^
當(dāng)初設(shè)計(jì)的時(shí)候,考慮到游戲里存在著2種移動(dòng)場(chǎng)景,一個(gè)是海上,一個(gè)是城市。城市的特點(diǎn)是有邊界,海上地圖的特點(diǎn)是超大無(wú)縫地圖,所以在設(shè)計(jì)的時(shí)候,我們有限考慮的是海上場(chǎng)景的地圖設(shè)計(jì)。城市地圖可以看做是海上地圖的一個(gè)特例,地圖的四周只有少量或者根本沒(méi)有相關(guān)的連接地圖。
超大地圖的設(shè)計(jì)是采取對(duì)地圖進(jìn)行分塊處理,把整個(gè)海洋世界分解為多塊小地圖,每塊地圖的大小和一個(gè)游戲屏幕(800×600)的大小差不多。服務(wù)器里存放有所有地圖的信息,當(dāng)一位玩家參數(shù)移動(dòng)的時(shí)候,會(huì)把自己的移動(dòng)請(qǐng)求信息發(fā)送到相關(guān)的9塊地圖上(自己所在的地圖,以及以自己為中心鄰接的8張地圖),這樣每個(gè)客戶端都能接收到來(lái)自自己周圍9張地圖上其他玩家的移動(dòng)信息,從而實(shí)現(xiàn)了系統(tǒng)的互動(dòng)。
概念上說(shuō)起來(lái)是很簡(jiǎn)單,但是到實(shí)踐的時(shí)候要考慮的地方就很多了,例如移動(dòng)方向,阻擋,最麻煩的就是地圖切換了,需要通知相關(guān)地圖的玩家進(jìn)入以及相關(guān)地圖上的玩家退出等游戲事件,而且還存在則跨越地圖后的移動(dòng)處理等問(wèn)題。總之因?yàn)槲抑皇翘峁┓桨刚撸唧w編碼不是我來(lái)做,所以我對(duì)里面的具體細(xì)節(jié)了解得不是很詳細(xì),只能大概的理一下他的思路。
服務(wù)器還是基于面向?qū)ο蟮脑O(shè)計(jì)思路來(lái)做的,整個(gè)系統(tǒng)里分了3個(gè)對(duì)象,玩家、地圖、地圖管理。玩家對(duì)象和我上面的概念一樣,是存儲(chǔ)玩家信息,并存在著一定的于地圖相關(guān)的處理函數(shù)。地圖對(duì)象存放的是一小張地圖的信息,和與當(dāng)張地圖操作相關(guān)的操作。地圖管理可以看做是超大地圖類,它的作用就是管理無(wú)數(shù)個(gè)地圖對(duì)象,讓它們?cè)谶壿嬌掀唇映蔀橐粡埑蟮牡貓D。
同時(shí)除了這3個(gè)對(duì)象外,還存在著一個(gè)狀態(tài)機(jī)的過(guò)程。我們對(duì)這個(gè)狀態(tài)機(jī)的理解很簡(jiǎn)單,就是每隔一定的周期計(jì)算一次玩家的新位置,讓他們看起來(lái)是在連續(xù)不斷的運(yùn)動(dòng)。這個(gè)東西不是很難理解,但是處理起來(lái)確看起來(lái)有些讓人困擾,首先是服務(wù)器端的在虛擬機(jī)執(zhí)行時(shí)間中斷的時(shí)間間隔與客戶端的不同,設(shè)計(jì)的時(shí)候,服務(wù)器端是每隔0.5s執(zhí)行一次,而客戶端如果也按照服務(wù)器端的設(shè)計(jì)出處理,明顯會(huì)讓玩家感覺(jué)地圖上的人物一卡一卡的在進(jìn)行跳躍運(yùn)動(dòng),所以客戶端在虛擬機(jī)的時(shí)間間隔勢(shì)必要比服務(wù)器短很多,我們的設(shè)計(jì)是0.1S執(zhí)行一次。這樣的短的間隔就會(huì)造成客戶端的移動(dòng)數(shù)據(jù)與服務(wù)器端的移動(dòng)數(shù)據(jù)不一致。解決這個(gè)不同步的問(wèn)題采用了多種方案,其中包括定期發(fā)送玩家的位置的同步信息。不過(guò)也因?yàn)闀r(shí)間關(guān)系,這個(gè)同步方案沒(méi)有完全的實(shí)現(xiàn),所以系統(tǒng)還是存在著不同步的現(xiàn)象。
不過(guò)地圖服務(wù)器里的注解還是比較詳細(xì)的,所以這里要說(shuō)明的不是很多,理解它架構(gòu)就好理解了。理解架構(gòu)后再看一下“地圖服務(wù)器工作日志.doc”會(huì)對(duì)這個(gè)開(kāi)發(fā)過(guò)程有一定的了解。
posted on 2009-02-12 02:38
小王 閱讀(568)
評(píng)論(0) 編輯 收藏 引用