基于ARM和WinSock的多人對(duì)戰(zhàn)游戲平臺(tái)設(shè)計(jì)
摘要:具有多機(jī)互聯(lián)對(duì)戰(zhàn)功能的開放式便攜游戲機(jī)具有廣闊的應(yīng)用價(jià)值和深遠(yuǎn)的發(fā)展空間。以SAMSUNG公司基于ARM920T的處理器S3C2410為核心,嵌入WinCE 5.0操作系統(tǒng),在VS2008開發(fā)環(huán)境下創(chuàng)建智能設(shè)備MFC工程,并將在Win32環(huán)境下開發(fā)的單人/雙人五子棋游戲進(jìn)行代碼移植,最終在ARM開發(fā)板上成功運(yùn)行游戲。游戲開發(fā)基于Windows Sockets網(wǎng)絡(luò)鳊程,能夠?qū)崿F(xiàn)ARM板與PC、ARM板與ARM板之間的游戲?qū)?zhàn),可利用以太網(wǎng)接口互聯(lián),也可以通過無線局域網(wǎng)互聯(lián)。該文以五子棋游戲?yàn)槔?,詳述了硬件?gòu)建、游戲開發(fā)及移植的整個(gè)過程,極具借鑒價(jià)值。
關(guān)鍵詞:ARM處理器;WinCE5.0操作系統(tǒng);網(wǎng)絡(luò)鳊程;代碼移植
游戲不僅能開發(fā)人的智力,使人頭腦反應(yīng)靈敏,還能滿足人的精神需求(如冒險(xiǎn)、創(chuàng)造力、情感等),極具娛樂性和趣味性,深受人們的喜愛。隨著消費(fèi)類電子產(chǎn)業(yè)的蓬勃發(fā)展,越來越多的嵌入式電子產(chǎn)品走進(jìn)了千家萬戶,催生出了諸如GBA(Game Boy Advance)、PSP(Play-Station Portabk)以及最近才在我國(guó)上市的iPad等一大批專業(yè)的并且銷量驚人的明星級(jí)移動(dòng)娛樂游戲設(shè)備。
然而上述游戲平臺(tái)通常造價(jià)昂貴,且不具有開放性。例如備受推崇的PSP,開發(fā)授權(quán)問題和昂貴的專用開發(fā)套件(軟硬件)使得PSP游戲的開發(fā)門檻很高。這在很大程度上限制了這些游戲平臺(tái)的普及。如果利用通用的處理器和常用的嵌入式操作系統(tǒng)(如WinCE、Linux等)構(gòu)建一種基于以太網(wǎng)或者無線以太網(wǎng)的便攜式的游戲機(jī)。則可以吸引大量熟悉C/C++嵌入式編程的工程師或發(fā)燒友制作出各種精彩的游戲,這必將極大地推動(dòng)這種游戲平臺(tái)的普及。而且將平臺(tái)進(jìn)行功能裁剪和批量生產(chǎn)后成本較低,對(duì)于中低收入人群來說將是極佳選擇,市場(chǎng)潛力無窮。
本文詳述了這種游戲平臺(tái)的硬件構(gòu)建、互聯(lián)對(duì)戰(zhàn)游戲開發(fā)框架和流程,以及從Win32到WinCE進(jìn)行代碼移植的整個(gè)開發(fā)過程,并記錄了開發(fā)過程中積累的經(jīng)驗(yàn),具有很高的借鑒價(jià)值。
1 硬件平臺(tái)
硬件平臺(tái)架構(gòu)如圖1所示。
S3C2410是Samsung公司推出的16/32位RISC處理器,為手持設(shè)備和一般類型應(yīng)用提供了低價(jià)格、低功耗、高性能小型微控制器的解決方案。
S3C2410采用了ARM920T內(nèi)核,0.18μm工藝的CMOS標(biāo)準(zhǔn)宏單元和存儲(chǔ)器單元。它的低功耗、精簡(jiǎn)和出色的全靜態(tài)設(shè)計(jì)特別適用于對(duì)低成本和功耗敏感的應(yīng)用。ARM920T實(shí)現(xiàn)了MMU,AMBA BUS和Harvard高速緩沖體系結(jié)構(gòu)。這一結(jié)構(gòu)具有獨(dú)立的16 kB的指令Cache和16 kB數(shù)據(jù)Cache,每個(gè)都由8字長(zhǎng)的行構(gòu)成。
2 套接字編程
2.1 WinSock基礎(chǔ)
WinSock是Windows Sockets的縮寫,是Windows環(huán)境下廣泛應(yīng)用的、開放的、支持多種協(xié)議的網(wǎng)絡(luò)編程接口規(guī)范。這里主要使用TCP/IP協(xié)議族實(shí)現(xiàn)通信。
基于TCP/IP的套接字有流式套接字(SOCK_STREAM)、數(shù)據(jù)報(bào)式套接字(SOCK_DGRAM)、原始式套接字(SOCK_RAW)3種類型,如圖2所示。
TCP協(xié)議是面向連接的網(wǎng)絡(luò)協(xié)議,它的連接步驟較多,而且當(dāng)檢測(cè)到數(shù)據(jù)包丟失或錯(cuò)誤時(shí),會(huì)要求發(fā)送端重新發(fā)送,這樣一來就不可避免地引起了傳輸延時(shí)。
UDP協(xié)議面向無連接服務(wù),每個(gè)分組都攜帶有完整的目的地址,操作簡(jiǎn)單,且無傳輸延遲,比較適合要求不高的游戲通信。它的通信時(shí)序如圖3所示。
[!--empirenews.page--]
2.2 應(yīng)用程序接口函數(shù)
1)加載套接字庫(kù)AfxSocketlnit()
布爾型,參數(shù)缺省值為NULL,在程序結(jié)束前自動(dòng)調(diào)用WSACleanup清除套接字。
2)創(chuàng)建套接字socket()
用于創(chuàng)建指定類型的套接字,流式(TCP協(xié)議)SOCK_STREAM或數(shù)據(jù)報(bào)式(UDP協(xié)議)SOCK_DGRAM。
3)綁定本地地址bind()
將套接字地址(包括本地主機(jī)地址和本地端口地址)與所創(chuàng)建的套接字號(hào)聯(lián)系起來,即將名字賦予套接字,以指定本地半相關(guān)。
4)接收recvfrom()
在套接字指定的已連接的數(shù)據(jù)報(bào)或流套接字上接收輸入數(shù)據(jù)。
5)發(fā)送sendto()
在套接字指定的已連接的數(shù)據(jù)報(bào)或流套接字上發(fā)送輸出數(shù)據(jù)。
3 Win32下五子棋程序設(shè)計(jì)
3.1 游戲設(shè)計(jì)思路
游戲開始前有一系列引導(dǎo)步驟,讓用戶選擇游戲模式,并作相應(yīng)的初始連接,如圖4所示。這些引導(dǎo)步驟可通過添加一系列對(duì)話框資源來實(shí)現(xiàn)。完成之后進(jìn)入選擇的游戲模式。
對(duì)于單人五子棋游戲,即人機(jī)對(duì)戰(zhàn),只需要一個(gè)應(yīng)用程序。當(dāng)用戶鼠標(biāo)左擊棋盤時(shí),程序先在相應(yīng)位置處畫棋子,然后執(zhí)行電腦方策略,實(shí)現(xiàn)對(duì)戰(zhàn)。
對(duì)于雙人五子棋游戲,則需要先運(yùn)行一個(gè)服務(wù)器端程序,然后兩個(gè)用戶分別運(yùn)行一個(gè)客戶端程序,并與此服務(wù)器相連。游戲進(jìn)行過程中,由服務(wù)器執(zhí)行游戲策略,客戶端程序只負(fù)責(zé)采集鼠標(biāo)信息和顯示棋子。我們讓用戶A在游戲平臺(tái)A上運(yùn)行服務(wù)器端程序,緊接著運(yùn)行客戶端程序,并與服務(wù)器建立Socket連接;然后告訴用戶B服務(wù)器的IP地址,讓其在平臺(tái)B上運(yùn)行客戶端程序,并與服務(wù)器建立Socket連接;連接成功后就可以開始游戲了。
3.2 單人游戲
建立MFC工程,選擇創(chuàng)建單文檔類型的應(yīng)用程序。添加對(duì)話框資源用于選擇游戲模式,并在View類構(gòu)造函數(shù)中DoModal()。
進(jìn)入單人模式后的程序開發(fā)流程如圖5所示。
[!--empirenews.page--]
對(duì)于某些步驟需要作詳細(xì)說明:
3)判斷游戲是否結(jié)束
在Doc類中定義私有性質(zhì)的成員變量int state[15][10];,用于記錄棋盤上每一格的狀態(tài):無棋(值為0)、用戶方棋(值為1)、電腦方棋(值為2),初始值是0。游戲過程中,某一方落棋后立即給state數(shù)組對(duì)應(yīng)成員賦值,下標(biāo)可由鼠標(biāo)左鍵消息響應(yīng)函數(shù)的CPoint point參數(shù)轉(zhuǎn)換而來。
對(duì)于棋盤上每一個(gè)坐標(biāo)點(diǎn)(i,j),沿東西、南北、東南西北、東北西南四個(gè)方向掃描五個(gè)沿途點(diǎn)的狀態(tài)值,若發(fā)現(xiàn)五個(gè)相同狀態(tài)相連,則該狀態(tài)(用戶方或電腦方)的棋手獲勝,游戲結(jié)束。
4)電腦方下棋策略
對(duì)于棋盤上每一個(gè)坐標(biāo)點(diǎn)(i,j),掃描它的狀態(tài)值state[i][j],一經(jīng)發(fā)現(xiàn)不為0,就以此點(diǎn)為起點(diǎn),沿東、南、西、北、東南、西南、東北、西北8個(gè)方向搜索5個(gè)棋位。
事先定義針對(duì)每個(gè)點(diǎn)、每個(gè)方向的8個(gè)整型數(shù)組(初始值賦為0):
對(duì)于坐標(biāo)點(diǎn)(i,j),搜索過程中若遇到具有相同狀態(tài)的點(diǎn)(m,n),則對(duì)應(yīng)方向數(shù)組的[i][j]成員的值增加,遇到不同狀態(tài)點(diǎn)則減小。保存8個(gè)中絕對(duì)值最大的。
上述操作完后,比較所有點(diǎn)存的值,絕對(duì)值最大的說明以該點(diǎn)起始的某個(gè)方向己方棋子相連較多,或者對(duì)方棋子相連較多,最適合落子。
3.3 雙人游戲
從游戲開始到結(jié)束,客戶端與服務(wù)器的交互過程如圖6所示。
3.3.1 服務(wù)器端程序
創(chuàng)建基于對(duì)話框的MFC工程。
在App類的BOOL InitInstance()中加載套接字庫(kù):AfxSocketInit();
在Dlg類的BOOL OnInitDialog()中初始化套接字,包括新建和綁定套接字:socket()、bind();
在對(duì)話框上畫兩個(gè)按鈕控件:“連接用戶”和“開始游戲”。
開發(fā)流程如圖7所示。[!--empirenews.page--]
對(duì)于某些步驟需要作詳細(xì)說明:
1)開辟線程
如果讓服務(wù)器一直recvfrom(),則主線程將一直執(zhí)行此函數(shù),造成消息擁堵,從而導(dǎo)致其他事件難以響應(yīng),因此選擇開辟新線程在后臺(tái)接收客戶端信息,合理分配系統(tǒng)資源。
開辟線程的過程如下:
①定義要傳送給線程的全局性質(zhì)的結(jié)構(gòu)體RECVPARAM,成員為Dlg類指針類型變量。
②定義RECVPARAM結(jié)構(gòu)體變量pRecvParam,并把當(dāng)前工程的Dlg類指針賦給其成員;創(chuàng)建線程,把pRecvParam傳遞給線程;然后關(guān)閉線程。
③在線程回調(diào)函數(shù)中接收傳遞來的變量pRecvParam,然后就可以調(diào)用Dlg類的成員來實(shí)現(xiàn)功能。
2)信息格式
①客戶端連接信息
格式隨意的字符串,目的是讓服務(wù)器端接收到數(shù)據(jù),從而發(fā)現(xiàn)客戶端IP地址。我們發(fā)的是“0000”。
②客戶端下棋信息
信息格式:用戶標(biāo)識(shí)(1位)、落子橫坐標(biāo)(2位)、落子縱坐標(biāo)(2位)。
其中,用戶標(biāo)識(shí)位1代表先手(白方),0代表后手(黑方)。
③服務(wù)器端發(fā)送信息
指導(dǎo)客戶端畫棋子以及顯示狀態(tài)。
信息格式:用戶標(biāo)識(shí)(1位)、落子橫坐標(biāo)(2位)、落子縱坐標(biāo)(2位)、游戲狀態(tài)(1位)。
其中,前5位與從客戶端接收的相同:游戲狀態(tài)位1表示游戲結(jié)束,0表示游戲未結(jié)束。
3.3.2 客戶端程序
創(chuàng)建基于單文檔的MFC工程。
在App類的BOOL InitInstance()中加載套接字庫(kù):AfxSocketInit();
添加對(duì)話框資源CDlgMode,用于選擇游戲模式:
添加對(duì)話框資源CDlgLink,用于連接服務(wù)器;并在其上畫一個(gè)IP地址控件,用于填寫服務(wù)器IP;在確定按鈕的響應(yīng)函數(shù)中初始化套接字socket()、bind(),并向服務(wù)器發(fā)送連接請(qǐng)求sendto();
在View類構(gòu)造函數(shù)中將模式選擇對(duì)話框DoModal(),選擇進(jìn)入雙人模式,之后的程序開發(fā)流程如圖8所示。
4 代碼移植
4.1 WindowsCE簡(jiǎn)介
Windows CE是基于Win32 API重新開發(fā)的新型信息設(shè)備平臺(tái),具有模塊化、結(jié)構(gòu)化和基于Win32應(yīng)用程序接口以及與處理器無關(guān)等特點(diǎn)。大量用戶對(duì)于Windows操作方式和編程的熟悉,是Windows CE作為嵌入式操作系統(tǒng)迅速發(fā)展的最大的優(yōu)勢(shì),也是選擇的原因。
4.2 代碼移植
安裝WinCE5.0的標(biāo)準(zhǔn)SDK,在VS2008開發(fā)環(huán)境下創(chuàng)建智能設(shè)備的MFC工程,選擇基于對(duì)話框或單文檔的應(yīng)用程序,并選擇剛剛安裝的標(biāo)準(zhǔn)SDK平臺(tái)。工程創(chuàng)建完成后,將在Win32下開發(fā)的代碼按同樣的方式轉(zhuǎn)移過來,然后編譯,修改錯(cuò)誤。
WinCE是Unicode環(huán)境,盡管WinCE支持ASCII功能來進(jìn)行文件交換,但是WinCE的本地文件格式是Unicode。所以,要將字符串轉(zhuǎn)換為UmcMe才能使用。另外就是代碼移植過程中丟三落四的粗心錯(cuò)誤。以下列舉代碼移植過程中遇到的問題及解決方法:
1)某些函數(shù)發(fā)生變化,不再識(shí)別ASCII碼字符或字符串,例如MessageBox,其字符串參數(shù)必須經(jīng)_T(“”)轉(zhuǎn)換成Unicode;另外Cstring類不要輕易使用;
2)某些功能使用不同函數(shù),例如整型轉(zhuǎn)字符串型,由函數(shù)itoa變?yōu)開itoa_s;
3)智能設(shè)備項(xiàng)目中沒有IP地址控件,用編輯框代替,多了些字符串拼接、轉(zhuǎn)換的工作;
4)不要忘了使客戶端與服務(wù)器端的端口號(hào)保持一致。
5 硬件調(diào)試及結(jié)果
5.1 PC與ARM板連接
1)平臺(tái)連接
通過網(wǎng)線相連,然后指定網(wǎng)關(guān)地址和IP地址。指定方法如下:本地連接一>點(diǎn)右鍵看屬性—>雙擊“Internet協(xié)議(TCP/IP)”一>使用下面的IP地址,自己填寫即可。特別注意,當(dāng)兩臺(tái)機(jī)器直接用網(wǎng)線相連而不使用路由器時(shí),必須同一個(gè)網(wǎng)關(guān)才可實(shí)現(xiàn)數(shù)據(jù)交換??赏ㄟ^ping命令測(cè)試網(wǎng)絡(luò)是否連通。
2)運(yùn)行游戲
利用同步軟件Microsoft AcfiveSync將開發(fā)的WinCE5.0下游戲程序傳到ARM平臺(tái)中,即可在上面運(yùn)行。
5.2 ARM板與ARM板連接
與上述過程類同。
6 結(jié)論
經(jīng)實(shí)際操作驗(yàn)證,這種多人游戲開發(fā)方式(多線程)使得資源占用率很低,S3C2410處理器完全可以勝任,整個(gè)游戲運(yùn)行流暢。游戲平臺(tái)可以通過有線方式互聯(lián),也可以通過無線方式互聯(lián),操作簡(jiǎn)單,使用方便。而且這種游戲平臺(tái)具有很高的開放性,利用上述的開發(fā)框架可以輕易開發(fā)出更多更好玩的游戲。