單機(jī)對(duì)戰(zhàn)游戲畢業(yè)設(shè)計(jì)_第1頁(yè)
已閱讀1頁(yè),還剩17頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1、<p><b>  目錄</b></p><p><b>  摘要1</b></p><p><b>  關(guān)鍵字1</b></p><p><b>  1 前言1</b></p><p>  1.1程序開(kāi)發(fā)背景1</p>&

2、lt;p>  1.2 程序開(kāi)發(fā)目標(biāo)1</p><p>  1.3編碼設(shè)計(jì)標(biāo)準(zhǔn)與規(guī)范2</p><p>  1.4程序開(kāi)發(fā)的實(shí)際意義2</p><p>  1.5 對(duì)“單擊對(duì)戰(zhàn)”的解釋3</p><p>  2 相關(guān)軟件及技術(shù)介紹3</p><p>  2.1 開(kāi)發(fā)平臺(tái)與工具選擇3</p>

3、<p>  2.1.1 .NET簡(jiǎn)介3</p><p>  2.1.2 Microsoft Visual Studio 2008簡(jiǎn)介3</p><p>  2.2 相關(guān)技術(shù)簡(jiǎn)介3</p><p>  2.2.1 使用UDP協(xié)議的套接字技術(shù)3</p><p>  2.2.2 使用TCP協(xié)議的套接字技術(shù)3</p>

4、<p>  2.2.3 Socket方法和相關(guān)類介紹4</p><p>  2.2.4 多線程的使用4</p><p>  2.2.5 事件的使用4</p><p>  2.2.6 反射調(diào)用一個(gè)類的私有成員4</p><p>  3 可行性分析與需求分析4</p><p>  3.1 可行性分析

5、4</p><p>  3.2 需求分析5</p><p>  3.2.1 功能需求5</p><p>  4 單擊對(duì)戰(zhàn)游戲設(shè)計(jì)5</p><p>  4.1 系統(tǒng)設(shè)計(jì)思想5</p><p>  4.2 系統(tǒng)總體設(shè)計(jì)5</p><p>  5 主要功能詳細(xì)設(shè)計(jì)6</p>

6、<p>  5.1 在線用戶列表的獲得6</p><p>  5.1.1 設(shè)計(jì)思路6</p><p>  5.1.2 實(shí)現(xiàn)過(guò)程6</p><p>  5.2 進(jìn)入對(duì)戰(zhàn)窗體的友好用戶體驗(yàn)9</p><p>  5.2.1 設(shè)計(jì)思路9</p><p>  5.2.2關(guān)鍵代碼9</p>

7、<p>  5.3 五子棋對(duì)戰(zhàn)窗體功能12</p><p>  5.3.1 設(shè)計(jì)思路12</p><p>  5.3.2 關(guān)鍵代碼12</p><p><b>  6系統(tǒng)測(cè)試15</b></p><p>  6.1測(cè)試分析報(bào)告15</p><p>  6.2.1測(cè)試方式簡(jiǎn)介

8、15</p><p>  6.2改進(jìn)意見(jiàn)15</p><p><b>  7結(jié)束語(yǔ)15</b></p><p><b>  致謝15</b></p><p><b>  參考文獻(xiàn)15</b></p><p>  單擊對(duì)戰(zhàn)游戲的設(shè)計(jì)與實(shí)現(xiàn)</

9、p><p>  摘要:系統(tǒng)是基于.NET平臺(tái)開(kāi)發(fā)的一個(gè)P2P結(jié)構(gòu)的單擊對(duì)戰(zhàn)五子棋游戲?;赑2P、套接字、事件、設(shè)計(jì)模式、多線程、反射等技術(shù),使用c#語(yǔ)言和UDP協(xié)議的套接字進(jìn)行廣播,不但可以實(shí)現(xiàn)在局域網(wǎng)內(nèi)獲得所有在線用戶IP列表、狀態(tài)的功能,而且通過(guò)使用TCP協(xié)議的套接字可以實(shí)現(xiàn)多個(gè)用戶之間的連接、游戲、聊天、并閃動(dòng)對(duì)方屏幕的功能。以計(jì)算機(jī)技術(shù)和網(wǎng)絡(luò)技術(shù)為核心的現(xiàn)代網(wǎng)絡(luò)技術(shù)已在現(xiàn)實(shí)生活和生產(chǎn)中得以廣泛的使用,休閑類

10、網(wǎng)絡(luò)游戲集趣味性、娛樂(lè)性、互動(dòng)性和益智性于一體,已經(jīng)成為多數(shù)人群的休閑方式。</p><p>  關(guān)鍵字:P2P;UDP廣播;TCP協(xié)議;設(shè)計(jì)模式;事件</p><p><b>  1 前言</b></p><p><b>  1.1程序開(kāi)發(fā)背景</b></p><p>  隨著計(jì)算機(jī)信息技術(shù)的發(fā)展

11、,網(wǎng)絡(luò)游戲已成為我們生活中的重要組成部分,但由于廣域網(wǎng)游戲占用的資源較多、易受到病毒等缺點(diǎn),所以局域網(wǎng)游戲被游戲愛(ài)好者廣泛使用。無(wú)論是對(duì)于初步探索網(wǎng)絡(luò)編程的編程愛(ài)好者還是有志于在物聯(lián)網(wǎng)方面發(fā)展的程序員,編寫(xiě)簡(jiǎn)單的局域網(wǎng)游戲都是一個(gè)很好開(kāi)始。</p><p>  網(wǎng)絡(luò)游戲在市面上已經(jīng)出現(xiàn)多年,許多游戲?qū)?zhàn)平臺(tái)也已相繼出現(xiàn),例如我們熟知的浩方、QQ對(duì)戰(zhàn)平臺(tái)和街機(jī)游戲的ArcadeLive平臺(tái)等等,雖說(shuō)它們有很大的不同

12、,但有一點(diǎn)是可以肯定的:不管是這些游戲還是對(duì)戰(zhàn)平臺(tái),剛開(kāi)始都是需要在局域網(wǎng)內(nèi)調(diào)試的。然而,出于盈利的目的,開(kāi)發(fā)商一般不會(huì)將對(duì)戰(zhàn)平臺(tái)的局域網(wǎng)內(nèi)的版本流于市面,更不會(huì)公開(kāi)自己的原代碼。當(dāng)然通過(guò)一些人士的分析和透露,我們知道浩方是通過(guò)把tcp/ip協(xié)議轉(zhuǎn)換為ipx協(xié)議。虛擬局域網(wǎng),為大家提供了一個(gè)作戰(zhàn)平臺(tái),但游戲開(kāi)始后,玩家之間就是p2p的關(guān)系了,游戲速度和平臺(tái)無(wú)關(guān)。但具體的實(shí)現(xiàn)肯定是很困難的,里面至少涉及hook,P2P,VPN,修改數(shù)據(jù)包

13、,java或C++的網(wǎng)絡(luò)編程,進(jìn)程通信,數(shù)據(jù)庫(kù)的操作等等。當(dāng)然一些大型游戲里面內(nèi)置了網(wǎng)絡(luò)連接模塊,在局域網(wǎng)內(nèi)是不需要再通過(guò)平臺(tái)完成數(shù)據(jù)通信的。但對(duì)于一些單機(jī)游戲,要想完成局域網(wǎng)內(nèi)的對(duì)戰(zhàn),對(duì)戰(zhàn)平臺(tái)就不可或缺了。這方面ArcadeLive是比較有代表性的,它的聯(lián)網(wǎng)功能可能是靠"kaillera"來(lái)實(shí)現(xiàn)的,要想實(shí)現(xiàn)聯(lián)網(wǎng)玩游戲,你必須有一個(gè)kaillera的客戶端和一個(gè)服務(wù)器端的程序,客戶端現(xiàn)在大多在模擬器中自</p&

14、gt;<p>  1.2 程序開(kāi)發(fā)目標(biāo)</p><p>  擬開(kāi)發(fā)基于p2p具有運(yùn)用時(shí)自動(dòng)加載在線用戶IP列表、雙擊某個(gè)IP或頭像自動(dòng)進(jìn)入五子棋游戲,并且用戶體驗(yàn)很好的程序。</p><p>  該程序無(wú)需服務(wù)器端,也就是說(shuō)每個(gè)程序?qū)嵗仁欠?wù)端也是客戶端,也就是常被我們提及的p2p。運(yùn)行程序時(shí)通過(guò)廣播特定的信息使所有在線的用戶獲得自己的IP然后添加到自己的用戶列表上,收到此

15、特定信息的用戶回復(fù)另一信息,然后就可以實(shí)現(xiàn)所有的人獲得在線用戶IP的功能。游戲是逐漸被世人拋棄的起源于中國(guó)古代的傳統(tǒng)黑白棋種之一的五子棋,雖然它看似無(wú)聊,但對(duì)于練習(xí)編程技術(shù)還是很有意義的。本程序中的五子棋使用TCP協(xié)議的套接字進(jìn)行通訊,廣泛應(yīng)用了事件機(jī)制,接收到我們自定義的信息后就會(huì)根據(jù)以至的信息頭作出相關(guān)的反映。眾所周之,網(wǎng)絡(luò)游戲會(huì)因?yàn)榉N種原因出現(xiàn)延遲,使用戶持續(xù)等待甚至出現(xiàn)卡死的情況,本程序盡最大的努力提高用戶體驗(yàn)的舒適性,即盡量不

16、發(fā)生卡的情況。</p><p>  1.3編碼設(shè)計(jì)標(biāo)準(zhǔn)與規(guī)范</p><p>  為了在編碼過(guò)程中,能夠快速地、有效地閱讀,我們有必要為對(duì)象約定一個(gè)規(guī)范的編碼命名約定。</p><p><b>  對(duì)象命名約定</b></p><p>  下面為在編碼過(guò)程中會(huì)用到的對(duì)象統(tǒng)一的命名,如下表1所示:</p>&

17、lt;p><b>  表1對(duì)象統(tǒng)一的命名</b></p><p><b>  結(jié)構(gòu)化編碼約定</b></p><p>  編碼風(fēng)格參照下例進(jìn)行:</p><p>  bool startListen = false;</p><p>  public bool CanAgin, CanAgin

18、s, CanDown, IFirst;</p><p>  private Socket socketListerner;</p><p>  private Thread mainThread;</p><p>  public ClientRole clientConnectionRole = new ClientRole();</p><p

19、>  在程序中,對(duì)一些比較難懂,或是屬性不熟悉的地方加上必要的文字說(shuō)明,其次,程序要有層次,使得讀程序時(shí)更易讀懂。</p><p>  1.4程序開(kāi)發(fā)的實(shí)際意義</p><p>  對(duì)于數(shù)據(jù)的通信,我們比較熟悉的有Tcp/Ip協(xié)議、UDP協(xié)議等等。以UDP協(xié)議為例,UDP從應(yīng)用程序接過(guò)報(bào)文后,附上目的端口號(hào)、源端口號(hào)和其他兩個(gè)小字段后就直接將結(jié)果段遞交給網(wǎng)絡(luò)層。網(wǎng)絡(luò)層將該段封裝到數(shù)據(jù)

20、報(bào)中后,盡力而為地將數(shù)據(jù)包傳遞給接收端主機(jī)。如果數(shù)據(jù)報(bào)到達(dá)接收端主機(jī),UPD將根據(jù)IP地址和兩個(gè)端口號(hào)將段中的數(shù)據(jù)交給相應(yīng)的進(jìn)程。本程序中的用戶列表的維護(hù)就是利用使用UDP協(xié)議的Socket發(fā)送廣播進(jìn)行獲得。然而鑒于UDP協(xié)議的無(wú)連接特點(diǎn),丟失數(shù)據(jù)包的可能性也很大的,所以當(dāng)進(jìn)入游戲窗體后,真正負(fù)責(zé)通訊的采用了TCP協(xié)議的套接字進(jìn)行通訊,也就是說(shuō),UDP協(xié)議那個(gè)套接字只負(fù)責(zé)維護(hù)列表。本程序中的游戲是人氣很旺的網(wǎng)絡(luò)五子棋,選擇它的原因很簡(jiǎn)單

21、:簡(jiǎn)單直接,不會(huì)上癮,算法簡(jiǎn)單,易于實(shí)現(xiàn)。</p><p>  本程序的可擴(kuò)展性強(qiáng),程序員可以根據(jù)自己的要求將基于TCP的Socket也提到一個(gè)類中,然后通過(guò)存放到一個(gè)以遠(yuǎn)程端點(diǎn)為Key相應(yīng)連接套接字為Value的Dictionary中,以實(shí)現(xiàn)和多人對(duì)戰(zhàn)的要求。當(dāng)然也可以利用反射將游戲程序編譯成一個(gè)類,然后放到一個(gè)特定文件夾下,當(dāng)主窗體運(yùn)行時(shí),自動(dòng)加載。除此之外,對(duì)于網(wǎng)絡(luò)編程的初學(xué)者也是很有幫助的。</p&

22、gt;<p>  1.5 對(duì)“單擊對(duì)戰(zhàn)”的解釋</p><p>  本程序采用p2p的架構(gòu),即集服務(wù)端和客戶端的功能于一體,整個(gè)設(shè)計(jì)采用事件驅(qū)動(dòng),所以非常方便實(shí)現(xiàn)。之所以叫做“單機(jī)對(duì)戰(zhàn)游戲的設(shè)計(jì)與實(shí)現(xiàn)”,主要是內(nèi)嵌的游戲是五子棋游戲,它在用戶體驗(yàn)上的感覺(jué)基本就是單擊鼠標(biāo),沒(méi)有太多別的負(fù)責(zé)的操作,很是適合小朋友或是老年人玩。</p><p>  2 相關(guān)軟件及技術(shù)介紹</

23、p><p>  2.1 開(kāi)發(fā)平臺(tái)與工具選擇</p><p>  2.1.1 .NET簡(jiǎn)介 .NET的編程模型將開(kāi)發(fā)語(yǔ)言和運(yùn)行時(shí)平臺(tái)分離,實(shí)現(xiàn)了獨(dú)立與語(yǔ)言的組件技術(shù),通過(guò)不同的運(yùn)行平臺(tái),.NET應(yīng)用可以被擴(kuò)展到PC、PDA、手機(jī)和嵌入式設(shè)備上。.NET運(yùn)行平臺(tái)稱為.NET Framework,是.NET平臺(tái)的基礎(chǔ)框架,它創(chuàng)造了一個(gè)完全可操控的安全的和特性豐富的應(yīng)用執(zhí)行環(huán)境,這不但使得應(yīng)用程

24、序的開(kāi)發(fā)與發(fā)布更加簡(jiǎn)單,并且實(shí)現(xiàn)了眾多語(yǔ)言的無(wú)縫連接。</p><p>  2.1.2 Microsoft Visual Studio 2008簡(jiǎn)介 為了開(kāi)發(fā).NET的應(yīng)用,微軟推出了強(qiáng)大的.NET開(kāi)發(fā)工具Visual Studio .NET(以下簡(jiǎn)稱VS)作為微軟.NET戰(zhàn)略的重要組成部分。VS包含C#、Visual Basic .NET、Visual c++.NET等多個(gè)開(kāi)發(fā)語(yǔ)言,同時(shí)還為第三方語(yǔ)言工具

25、商提供了接口,只要支持CLS(Common Language Specification)的語(yǔ)言都可以集成到VS環(huán)境中。</p><p>  VS充分發(fā)揮了CLR的潛力,為開(kāi)發(fā)者提供了一個(gè)統(tǒng)一的集成開(kāi)發(fā)環(huán)境和調(diào)試器。由于采用統(tǒng)一的類型定義和共享類庫(kù),各語(yǔ)言不僅在運(yùn)行時(shí),而且在設(shè)計(jì)就可以實(shí)現(xiàn)對(duì)象級(jí) 交互。VS不僅提供了Web Services開(kāi)發(fā)工具,而且提供從Web Services開(kāi)發(fā)到發(fā)布、注冊(cè)、整合的全過(guò)程

26、支持。為創(chuàng)建和部署Web Services,.Net平臺(tái)采用了一系列的互聯(lián)網(wǎng)協(xié)議,如XML、SOAP、WSDL、UDDL等用于Web Services的部署、請(qǐng)求和響應(yīng)。</p><p>  軟件人員最關(guān)心的還是開(kāi)發(fā)效率的提高,VS人性化的界面和眾多工具將成倍提高開(kāi)發(fā)效率。無(wú)論針對(duì)傳統(tǒng)的Windows桌面開(kāi)發(fā),Web Services,開(kāi)發(fā)人員都不必在為每種不用的應(yīng)用重寫(xiě)全部代碼,不必為不同的客戶設(shè)備定制不同的界

27、面。</p><p>  2.2 相關(guān)技術(shù)簡(jiǎn)介</p><p>  2.2.1 使用UDP協(xié)議的套接字技術(shù) 數(shù)據(jù)報(bào)式Socket(DATAGRAM)是一種無(wú)連接的Socket,對(duì)應(yīng)于無(wú)連接的UDP服務(wù)應(yīng)用.不安全(丟失,順序混亂,在接收端要分析重排及要求重發(fā)),但效率高。</p><p>  使用UDP協(xié)議的套接字可以用來(lái)向許多系統(tǒng)支持的網(wǎng)絡(luò)發(fā)送廣播數(shù)據(jù)包。要

28、實(shí)現(xiàn)這種功能,網(wǎng)絡(luò)本身必須支持廣播功能,因?yàn)橄到y(tǒng)軟件并不提供對(duì)廣播功能的任何模擬。廣播信息將會(huì)給網(wǎng)絡(luò)造成極重的負(fù)擔(dān),因?yàn)樗鼈円缶W(wǎng)絡(luò)上的每臺(tái)主機(jī)都為它們服務(wù),所以發(fā)送廣播數(shù)據(jù)包的能力被限制于那些用顯式標(biāo)記了允許廣播的套接字中。廣播通常是為了如下兩個(gè)原因而使用的:1. 一個(gè)應(yīng)用程序希望在本地網(wǎng)絡(luò)中找到一個(gè)資源,而應(yīng)用程序?qū)υ撡Y源的地址又沒(méi)有任何先驗(yàn)的知識(shí)。2. 一些重要的功能,例如路由要求把它們的信息發(fā)送給所有可以找到的本網(wǎng)段的主機(jī)。被廣

29、播信息的目的地址取決于這一信息將在何種網(wǎng)絡(luò)上廣播。本程序中利用基于UDP協(xié)議的套接字向廣播地址255.255.255.255發(fā)送廣播的方式以獲得用戶列表。</p><p>  2.2.2 使用TCP協(xié)議的套接字技術(shù) 本程序中的游戲部分使用的是的TCP協(xié)議的套接字進(jìn)行通訊。眾所周之流式Socket(STREAM)是一種面向連接的Socket,針對(duì)于面向連接的TCP服務(wù)應(yīng)用,雖然效率低但由于其安全特性被廣泛使用

30、。某一個(gè)棋子的位置很可能關(guān)系到游戲的勝敗,所以使用TCP協(xié)議的套接字就可以避免丟包等問(wèn)題。</p><p>  2.2.3 Socket方法和相關(guān)類介紹</p><p>  --------------------方法------------------------------</p><p>  Socket (): 創(chuàng)建一個(gè)Socket</p>&

31、lt;p>  Bind(): 綁定一個(gè)本地的IP和端口號(hào)(IPEndPoint)</p><p>  Listen(): 讓Socket偵聽(tīng)傳入的連接嘗試,并指定偵聽(tīng)隊(duì)列容量</p><p>  Connect(): 初始化與另一個(gè)Socket的連接</p><p>  Accept(): 接收連接并返回一個(gè)新的socket</p><p&

32、gt;  Send(): 輸出數(shù)據(jù)到Socket</p><p>  Receive(): 從Socket中讀取數(shù)據(jù)</p><p>  Close(): 關(guān)閉Socket (銷毀連接)</p><p>  ------------------相關(guān)類--------------------------</p><p>  IPAddress類

33、:包含了一個(gè)IP地址</p><p>  IPEndPoint類:包含了一對(duì)IP地址和端口號(hào)</p><p>  2.2.4 多線程的使用 應(yīng)用多線程技術(shù)最大的誤區(qū)在于沒(méi)有分清適合的情況就盲目地使用多線程。除非運(yùn)行一個(gè)多處理器計(jì)算機(jī),否則在CPU密集的任務(wù)中使用兩個(gè)線程不能節(jié)省多少時(shí)間,理解這一點(diǎn)很重要。在單處理器計(jì)算機(jī)上,讓兩個(gè)線程同時(shí)進(jìn)行100萬(wàn)次運(yùn)算所花的時(shí)間與讓一個(gè)線程進(jìn)行2

34、00萬(wàn)次運(yùn)算是相同的,甚至使用兩個(gè)線程所用的的時(shí)間更長(zhǎng),因?yàn)橐幚砹硪粋€(gè)線程操作系統(tǒng)必須用一定的事件切換線程,即分配時(shí)間片。使用線程帶來(lái)的負(fù)面因素是必須額外考慮線程的并發(fā)、同步等線程安全問(wèn)題,從而使得程序更加復(fù)雜而難以維護(hù)。然而,有些場(chǎng)合則使用多線程技術(shù)非常合適,網(wǎng)絡(luò)應(yīng)用開(kāi)發(fā)就是其經(jīng)常出現(xiàn)的場(chǎng)合之一。當(dāng)一個(gè)線程等待從網(wǎng)絡(luò)中獲取數(shù)據(jù),同時(shí)其他線程可以繼續(xù)處理其他的任務(wù),此時(shí)可以節(jié)省很多時(shí)間。本程序中主要就是在針對(duì)Accept和Receiv

35、e這兩個(gè)會(huì)阻塞的方法使用多線程。</p><p>  2.2.5 事件的使用 由于不知道什么時(shí)候會(huì)有人發(fā)送信息給自己,所以程序中應(yīng)用事件來(lái)處理對(duì)方的消息,即監(jiān)聽(tīng)對(duì)方發(fā)送的消息,如果接受到的消息和自己要處理的一致,則執(zhí)行注冊(cè)在其上的方法。例如,A上線的時(shí)候,就會(huì)向廣播地址發(fā)送“Logon”消息,已經(jīng)在線上的B、C收到此消息后就行執(zhí)行自定義的OnGetList事件,然后此事件調(diào)用注冊(cè)在自己身上的GetListM

36、ethod方法,從而實(shí)現(xiàn)將A的IP地址加到自己的用戶列表上的功能。</p><p>  2.2.6 反射調(diào)用一個(gè)類的私有成員 當(dāng)用戶進(jìn)入對(duì)戰(zhàn)窗體后,主窗體的用戶列表不可用,即一次只能和一個(gè)用戶進(jìn)行游戲,(這只是我個(gè)人規(guī)定)。當(dāng)用戶退出對(duì)戰(zhàn)窗體后,必須要求主窗體的用戶列表重新可用,但我們注意到,窗體類的TreeView類型字段默認(rèn)是private,也就是其它類不可訪問(wèn)的,當(dāng)然我們可以將其改成internal或

37、更加訪問(wèn)級(jí)別使外界可以訪問(wèn)。但我們有更專業(yè)的手段:利用反射技術(shù)。.NET的一個(gè)反編譯工具Reflector就是利用發(fā)射實(shí)現(xiàn)的。</p><p>  3 可行性分析與需求分析</p><p><b>  3.1 可行性分析</b></p><p>  在很早以前五子棋軟件就已經(jīng)被開(kāi)發(fā)出來(lái)了,當(dāng)時(shí)的五子棋軟件僅提供了“人機(jī)模式”與“雙人模式”?!叭?/p>

38、機(jī)模式”是指,人與計(jì)算機(jī)進(jìn)行對(duì)弈,計(jì)算機(jī)按照事先編寫(xiě)好的算法程序來(lái)進(jìn)行下棋;“雙人模式”是指,兩個(gè)人通過(guò)交替使用同一臺(tái)計(jì)算機(jī)來(lái)進(jìn)行下棋。無(wú)論是選擇哪一種模式,所有的操作都必須在同一臺(tái)計(jì)算機(jī)上來(lái)往完成,棋局無(wú)法在異地計(jì)算機(jī)之間來(lái)進(jìn)行,故而也叫單機(jī)版五子棋軟件。</p><p><b>  3.2 需求分析</b></p><p>  軟件的需求分析是軟件生存期中重要的一

39、步,也是決定性的一步。只有通過(guò)需求分析才能把軟件功能和性能的總體概念描述為具體的軟件需求規(guī)格說(shuō)明,從而奠定軟件開(kāi)發(fā)的基礎(chǔ)。在此階段,了解用戶要求本軟件必須滿足的所有功能和限制,以及用戶對(duì)軟件功能和性能的要求,弄清用戶想要軟件“做什么”,準(zhǔn)確地表達(dá)用戶的要求。</p><p>  3.2.1 功能需求</p><p>  運(yùn)行游戲自動(dòng)獲得所有在線用戶列表并且自己的IP加到所有其他在上用戶玩家

40、列表上的功能。</p><p>  顯示請(qǐng)求對(duì)戰(zhàn)提示框。</p><p>  進(jìn)入對(duì)戰(zhàn)窗體,其他用戶無(wú)法再與其游戲。</p><p>  顯示玩家退出提示框。</p><p>  能通過(guò)網(wǎng)絡(luò)進(jìn)行下棋。</p><p>  符合五子棋的基本規(guī)則。</p><p>  提供玩家之間的聊天功能。<

41、;/p><p>  提供玩家之間閃屏功能。</p><p>  一個(gè)用戶退出程序,所有在線用戶列表中自動(dòng)清除退出用戶對(duì)應(yīng)的IP。</p><p>  用戶界面需求界面友好、親切。</p><p><b>  界面簡(jiǎn)潔、不花哨。</b></p><p>  操作界面直觀、不繁瑣。</p>

42、<p><b>  用戶體驗(yàn)良好。</b></p><p>  4 單擊對(duì)戰(zhàn)游戲設(shè)計(jì)</p><p>  現(xiàn)有的網(wǎng)絡(luò)編程模式主要分成兩類:一種是基于C/S(Client/Server客戶機(jī)/服務(wù)器)模式,另一種是B/S (Browser/Server,瀏覽器/服務(wù)器)模式;C/S 程序具有好的交互性,功能強(qiáng)大, 但是客戶端必須安裝客戶端軟件,服務(wù)器端也要運(yùn)行

43、,限制了其應(yīng)用;B/S 模式下要求客戶端具有瀏覽器,但瀏覽器在安全方面有一些限制,交互性與功能有一些限制。由于這兩種模式的種種弊端,單擊對(duì)戰(zhàn)游戲采用了p2p網(wǎng)絡(luò)技術(shù)來(lái)設(shè)計(jì)與實(shí)現(xiàn),網(wǎng)絡(luò)內(nèi)部使用UDP和TCP協(xié)議的Socket 通過(guò)傳輸層提供的服務(wù)進(jìn)行通訊。 </p><p>  4.1 系統(tǒng)設(shè)計(jì)思想</p><p>  主窗體運(yùn)行時(shí)開(kāi)啟是一個(gè)基于UDP協(xié)議的套接字用戶獲得所在網(wǎng)段所用玩家的I

44、P地址,雙擊一個(gè)IP進(jìn)入對(duì)戰(zhàn)窗體。同時(shí)對(duì)方收到請(qǐng)求對(duì)戰(zhàn)的提示框。</p><p>  對(duì)戰(zhàn)窗體通過(guò)一個(gè)socket 監(jiān)聽(tīng)其他用戶的連接的連接,一旦有人連接連接,為該用戶建立連接并啟動(dòng)一個(gè)特定的客戶socket,利用該連接不斷從客戶讀取數(shù)據(jù),雙方的交互。</p><p>  4.2 系統(tǒng)總體設(shè)計(jì)</p><p><b>  系統(tǒng)流程圖:</b>&

45、lt;/p><p><b>  圖1 系統(tǒng)流程圖</b></p><p>  5 主要功能詳細(xì)設(shè)計(jì)</p><p>  5.1 在線用戶列表的獲得</p><p>  5.1.1 設(shè)計(jì)思路 用戶列表即在線用戶的IP地址。由于本程序使用的端口號(hào)為1817,所以一般情況下只需要知道本網(wǎng)段內(nèi)所有運(yùn)行了本程序的主機(jī)的IP就能

46、實(shí)現(xiàn)要求。選擇廣播是最簡(jiǎn)單且效率最高的手段,接下來(lái)考慮的就是應(yīng)當(dāng)使用什么協(xié)議的Socket進(jìn)行廣播。因?yàn)橹皇谦@得列表是需要連接且要求效率較高,UDP顯然在這里最適合。</p><p>  5.1.2 實(shí)現(xiàn)過(guò)程</p><p><b>  界面設(shè)計(jì)</b></p><p>  新建一個(gè)空解決方案,命名為”GobangDemo”,在解決方案上右擊添

47、加一個(gè)“新建項(xiàng)目”,在出現(xiàn)的對(duì)話框上選擇“Windows 窗體應(yīng)用程序”命名為“Gobang1”。</p><p>  將默認(rèn)生成的窗體刪除,添加一個(gè)“Windows 窗體”并命名為FrmMain,將此窗體的FormBorderStyle屬性設(shè)為none。</p><p>  拖入一個(gè)Panel控件,命名為pnlWrap,將它的Dock屬性設(shè)為Full。然后依次再拖入三個(gè)Panle,分別命

48、名為pnlTop、pnlMain、pnlBelow,然后分別設(shè)置它們對(duì)應(yīng)的BackgroundImage的值。</p><p>  拖入一個(gè)PictureBox控件,命名為picClose,然后設(shè)置Image屬性以顯示它默認(rèn)的圖片。拖入一個(gè)ImageList控件,使用默認(rèn)名字imageList1,在其Images屬性中添加一個(gè)頭像圖片。拖入一個(gè)ContextMenuStrip控件,使用默認(rèn)命名contextMen

49、uStrip1,然后添加“顯示主界面”和“退出”兩個(gè)子菜單。拖入一個(gè)NotifyIcon控件,使用默認(rèn)命名notifyIcon1,設(shè)置Visable屬性為true,ContextMenuStrip屬性為contextMenuStrip1。</p><p>  拖入一個(gè)TreeView控件,命名為tvPlayer,設(shè)值ImageList屬性為imageList1,ImageIndex屬性為0。</p>

50、<p>  小結(jié):其實(shí)要實(shí)現(xiàn)一個(gè)漂亮的界面并不是什么復(fù)雜的問(wèn)題,只要一張很好看的圖片就可以,但一個(gè)好的編程習(xí)慣那就是將所有的控件都放到Panel中,所以就要將圖片切成三段,然后設(shè)置成對(duì)應(yīng)容器的背景顏色。下面分別介紹各控件的具體作用:notifyIcon1用于將程序圖標(biāo)顯示系統(tǒng)托盤(pán),picClose用于最小化到系統(tǒng)托盤(pán),tvPlayer顯示所有在線用戶IP,imageList1里的圖片作為用戶列表中的頭像,contextMen

51、uStrip1作為notifyIcon1的菜單。</p><p><b>  關(guān)鍵代碼</b></p><p>  GetUserList類中發(fā)送UDP廣播的方法SendToAll</p><p>  public void SendToAll(string state)</p><p><b>  {<

52、/b></p><p>  IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse ("255. 255. 255.255") , port);</p><p>  Byte[] sendBytes = Encoding.ASCII.GetBytes(state);</p><p><

53、b>  try</b></p><p><b>  {</b></p><p>  udpGetList.Send(sendBytes, sendBytes.Length, endPoint);</p><p><b>  }</b></p><p><b>  ……&l

54、t;/b></p><p><b>  }</b></p><p>  GetUserList類中處理信息的方法GetList中接收來(lái)自局域網(wǎng)的信息:</p><p>  IPEndPoint RemoteIpEndPoint = new IPEndPoint(IPAddress.Any, port);</p><p&

55、gt;  while (true)</p><p><b>  {</b></p><p>  Byte[] receiveBytes = udpGetList.Receive(ref RemoteIpEndPoint);</p><p>  string returnData = Encoding.ASCII.GetString(receiv

56、eBytes);</p><p>  //接下來(lái)判斷收到的信息,然后作出相應(yīng)的處理</p><p><b>  ……</b></p><p><b>  }</b></p><p>  處理“Logon”消息:</p><p>  GetListEventArgs getLi

57、st = new GetListEventArgs();</p><p>  getList.IP = RemoteIpEndPoint.Address.ToString();</p><p>  getList.Msg = returnData;</p><p>  OnGetList(this, getList);</p><p>  I

58、PEndPoint endPoint = new IPEndPoint(IPAddress.Parse(getList.IP), port);</p><p>  Byte[] sendBytes = Encoding.ASCII.GetBytes("Reply");</p><p>  udpGetList.Send(sendBytes, sendBytes.Leng

59、th, endPoint);</p><p>  處理“Reply”消息:</p><p>  GetListEventArgs getList = new GetListEventArgs();</p><p>  getList.IP = RemoteIpEndPoint.Address.ToString();</p><p>  if

60、(getList.IP != IPAddress.Loopback.ToString())</p><p><b>  {</b></p><p>  getList.Msg = returnData;</p><p>  OnGetList(this, getList);</p><p><b>  }<

61、;/b></p><p><b>  使用到的事件</b></p><p>  public event EventHandler<GetListEventArgs> OnGetList;</p><p>  其中的GetListEventArgs是一個(gè)繼承自EventArgs的自定義類:</p><p&g

62、t;  public class GetListEventArgs : EventArgs</p><p><b>  {</b></p><p>  public string Msg; //獲得發(fā)過(guò)來(lái)的信息</p><p>  public string IP; //獲得對(duì)方IP,用于顯示的主界面的用戶列表上</p>&l

63、t;p><b>  }</b></p><p>  窗體類FrmMain的中的</p><p>  TreeNode node = new TreeNode();</p><p>  node.Text = e.IP;</p><p>  node.Tag = (object)e.IP;</p>&l

64、t;p>  foreach (TreeNode n in tvPlayer.Nodes)</p><p><b>  {</b></p><p>  if (n.Text == node.Text || n.Text.Contains(node.Text))</p><p><b>  {</b></p>

65、<p><b>  return;</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  tvPlayer.Nodes.Add(node);</p><p>  小結(jié):在p2p理念下,使用廣播獲得用戶列表是目前

66、為止我發(fā)現(xiàn)的最高效的實(shí)現(xiàn)手段??梢钥吹街恍柘驈V播地址發(fā)送“Logon”信息,在線的所有用戶都會(huì)接收到此信息,然后執(zhí)行相應(yīng)的代碼,其中最重要的就是將發(fā)送此信息的用戶的IP加到自己的tvPlayer中。</p><p><b>  圖2 主界面</b></p><p>  5.2 進(jìn)入對(duì)戰(zhàn)窗體的友好用戶體驗(yàn)</p><p>  5.2.1 設(shè)計(jì)

67、思路 IP為117.67.187.188的用戶雙擊想要對(duì)戰(zhàn)用戶的IP(假設(shè)是117.67.187.180),這次操作共發(fā)送兩類信息: 180收到“Fight”消息,所有在線用戶收到“InRoom”消息。180進(jìn)入對(duì)戰(zhàn)窗體,此時(shí)他的“開(kāi)始”按鈕不可用。于是180的用戶將看到請(qǐng)求對(duì)戰(zhàn)的窗體,并且180發(fā)送“Thinking”廣播;所用用戶的用戶列表上180將添加[fighting]標(biāo)記,180將添加[thinking]標(biāo)記,此時(shí)這兩個(gè)

68、用戶暫時(shí)都不能再被別人請(qǐng)求對(duì)戰(zhàn)。如果180點(diǎn)擊對(duì)戰(zhàn)窗體的“同意”則進(jìn)入對(duì)戰(zhàn)窗體,此時(shí)180將收到“117.67.187.180同意了你的請(qǐng)求”的提示框,點(diǎn)擊確定,開(kāi)始按鈕可用;如果180點(diǎn)擊拒絕,180將收到“117.67.187.180同意了你的請(qǐng)求”的提示框,180的用戶列表再次可用(利用反射訪問(wèn)似有成員)。對(duì)戰(zhàn)雙方進(jìn)入對(duì)戰(zhàn)窗體后就開(kāi)始了各自的服務(wù)端角色。</p><p><b>  5.2.2關(guān)鍵

69、代碼</b></p><p>  雙擊117.67.187.180節(jié)點(diǎn)的操作</p><p>  if(!tvPlayer.SelectedNode.Text.Contains("fighting") && !tvPlayer.SelectedNode.Text.Contains("thinking"))</p>

70、;<p><b>  {</b></p><p>  GetWindow();</p><p>  frmFight.IpTag = tvPlayer.SelectedNode.Tag.ToString();</p><p>  frmFight.getUserList = this.getUserList;</p>

71、<p>  frmFight.frmMain = this; </p><p>  frmFight.SetFrmFightPicStartUnabled();</p><p>  getUserList.SendToAll("InRoom"); </p><p>  getUserList.SendToSelected(tvPlay

72、er.SelectedNode.Tag.ToString(), "Fight");</p><p>  tvPlayer.Enabled = false;</p><p>  frmFight.Show();</p><p><b>  }</b></p><p><b>  else<

73、;/b></p><p><b>  {</b></p><p>  MessageBox.Show("哥游戲中,請(qǐng)勿打擾!");</p><p><b>  }</b></p><p>  117.67.187.180收到“Fight”后的操作</p>&l

74、t;p>  getUserList.SendToAll("Thinking"); </p><p>  FrmCue frmCue = new FrmCue();</p><p>  tvPlayer.Enabled = false;</p><p>  frmCue.frmMain = this;</p><p>

75、  frmCue.Tag = e.IP;</p><p>  frmCue.lblIP.Text = e.IP;</p><p>  frmCue.getUserList = this.getUserList;</p><p>  frmCue.Show();</p><p>  所有在線用戶收到“InRoom”后的操作</p>

76、<p>  foreach (TreeNode node in tvPlayer.Nodes)</p><p><b>  {</b></p><p>  if (node.Text.Contains(e.IP))</p><p><b>  {</b></p><p>  node.T

77、ext = e.IP + "[fighting]";</p><p><b>  }</b></p><p><b>  }</b></p><p>  117.67.187.180點(diǎn)擊提示框的“同意”按鈕</p><p>  private void lblAgree_Clic

78、k(object sender, EventArgs e)</p><p><b>  {</b></p><p>  IPAddress[] myIp = Dns.GetHostAddresses(Dns.GetHostName());</p><p>  getUserList.SendToSelected(lblIP.Text.Trim(

79、), "Agree");</p><p>  if (frmFight == null || frmFight.IsDisposed)</p><p><b>  {</b></p><p>  if (myIp[0].ToString() == this.Tag.ToString())</p><p&g

80、t;<b>  {</b></p><p>  this.Close();</p><p><b>  return;</b></p><p><b>  }</b></p><p>  frmFight = FrmFight.GetInstance();</p>

81、<p>  frmFight.Ready();</p><p>  } </p><p>  frmFight.IpTag = this.Tag.ToString(); </p><p>  frmFight.getUserList = this.getUserList;</p><p>

82、;  frmFight.frmMain = this.frmMain;</p><p>  //getUserList.SendToAll("");</p><p>  getUserList.SendToAll("InRoom");</p><p>  frmFight.Show();</p><p>

83、;  this.Close();</p><p><b>  }</b></p><p>  117.67.187.180點(diǎn)擊提示框的“拒絕”按鈕</p><p>  private void lblIgnore_Click(object sender, EventArgs e)</p><p><b>  {

84、</b></p><p>  getUserList.SendToSelected(lblIP.Text.Trim(), "Refuse");</p><p>  getUserList.SendToAll("Free");</p><p>  SetFrmMainTreeViewEnabedIsTrue();&l

85、t;/p><p>  this.Close();</p><p><b>  } </b></p><p>  利用反射在frmCue中訪問(wèn)frnMain中的似有方法</p><p>  private void SetFrmMainTreeViewEnabedIsTrue()</p><p>

86、;<b>  {</b></p><p>  Type typeFrmMain = frmMain.GetType();</p><p>  MethodInfo methodNiDongDe = typeFrmMain. GetMethod(" SetTreeViewEnableIsTrue",BindingFlags.NonPublic | B

87、indingFlags.Instance);</p><p>  methodNiDongDe.Invoke(frmMain, null);</p><p><b>  }</b></p><p>  進(jìn)入對(duì)戰(zhàn)窗體那一刻開(kāi)始各自服務(wù)端的角色</p><p>  IPEndPoint ep = new IPEndPoint

88、(IPAddress.Any, mainPort );</p><p>  socketListerner = new Socket(AddressFamily.InterNetwork,</p><p>  SocketType.Stream, ProtocolType.Tcp);</p><p>  socketListerner.Bind(ep);</p

89、><p>  socketListerner.Listen(12);</p><p>  startListen = true;</p><p>  while (true)</p><p><b>  {</b></p><p>  Socket socketServer;</p>&

90、lt;p>  ClientConnection conn;</p><p><b>  try</b></p><p><b>  {</b></p><p>  socketServer = socketListerner.Accept();</p><p>  conn = new Cli

91、entConnection(socketServer); </p><p>  dicConnections.Add(socketServer.RemoteEndPoint.ToString(), conn);</p><p>  RemoteTag = socketServer.RemoteEndPoint.ToString();</p><

92、;p><b>  }</b></p><p><b>  catch</b></p><p><b>  {</b></p><p><b>  break;</b></p><p><b>  }</b></p>

93、<p>  dicConnections[socketServer.RemoteEndPoint.ToString()].OnAddChess += new EventHandler<AddChessEventArgs>(this.AddChess);</p><p>  …… dicConnections[socketServer.RemoteEndPoint.To

94、String()].StartReceive();</p><p><b>  }</b></p><p>  小結(jié):這段功能基本還是利用事件驅(qū)動(dòng),本程序中應(yīng)用的是微軟大力推薦的EventHandler委托,它有兩種使用方式:一種是直接在定義一種此類型的委托,另一種使用它對(duì)應(yīng)的泛型委托EventHandler<TEventArgs>。個(gè)人特別喜歡第二種用法

95、。如果說(shuō)使用事件是很高級(jí)的技術(shù),那么反射則是高級(jí)技術(shù)中的王者。DotNet最為人熟知的反編譯工具Reflector就是利用反射做出來(lái)的。通過(guò)反射我們可以獲得一個(gè)類或一個(gè)類實(shí)例的結(jié)構(gòu),也就是說(shuō),只要屬于程序集,我們就可以通過(guò)反射看到源代碼。</p><p>  圖3 180看到的對(duì)戰(zhàn)請(qǐng)求窗體</p><p>  圖4 180點(diǎn)擊同意后188看到的提示</p><p&g

96、t;  圖5 180點(diǎn)擊拒絕后188看到的提示</p><p>  5.3 五子棋對(duì)戰(zhàn)窗體功能</p><p>  5.3.1 設(shè)計(jì)思路 點(diǎn)擊開(kāi)始按鈕后,開(kāi)啟各自的客戶端角色。棋盤(pán)是通過(guò)GDI畫(huà)上去的,并且每個(gè)圖片都注冊(cè)一個(gè)單擊事件。單擊棋盤(pán)一個(gè)位置,對(duì)應(yīng)位置顯示對(duì)應(yīng)顏色的棋子圖片,發(fā)送并且判斷是否自己是否贏了</p><p>  5.3.2 關(guān)鍵代碼<

97、;/p><p>  開(kāi)始客戶端角色的關(guān)鍵代碼</p><p>  public void ConnectServer(string ip, int port)</p><p><b>  {</b></p><p>  socketClientRole=new Socket (AddressFamily.InterNetwo

98、rk, Socket Type.Stream, ProtocolType.Tcp); </p><p>  IPEndPoint ep = new IPEndPoint(IPAddress.Parse(ip), port);</p><p>  socketClientRole.Connect(ep);</p><p>  clientConnected = tru

99、e;</p><p><b>  }</b></p><p>  棋盤(pán)初始化(注冊(cè)事件)</p><p>  for (int i = 0; i < 15; i++)//棋盤(pán)</p><p><b>  {</b></p><p>  for (int j = 0; j

100、 < 15; j++)</p><p><b>  {</b></p><p>  PictureBox pictureBox1 = new PictureBox();</p><p>  pictureBox1.Location = new System.Drawing.Point(i * 29 + 150, j * 29 + 70);

101、</p><p>  pictureBox1.Name = "pictureBox" + (i + j * 15).ToString();</p><p>  pictureBox1.Size = new System.Drawing.Size(30, 30);</p><p>  pictureBox1.Image = imageList1.I

102、mages[2];</p><p>  pictureBox1.TabStop = false;</p><p>  forChess[i + j * 15] = 521; </p><p>  pictureBox1.Click += new EventHandler(ClickChessboard);</p><p>  this.pnl

103、Main.Controls.Add(pictureBox1);</p><p><b>  }</b></p><p><b>  }</b></p><p>  單擊棋盤(pán)圖片發(fā)送的信息代碼</p><p>  public void ClickChessboard(object sender, E

104、ventArgs e)</p><p><b>  {</b></p><p>  if (CanDown == true)</p><p><b>  {</b></p><p>  if (IFirst == true)</p><p><b>  {</

105、b></p><p>  PictureBox pictureBox1 = (PictureBox)sender;</p><p>  pictureBox1.Enabled = false;</p><p>  int s = Int32.Parse(pictureBox1.Name.Substring(10));</p><p> 

106、 ClientRole clientRole = clientConnectionRole;</p><p><b>  BBow++;</b></p><p>  if (BBow % 2 == 1)//black 奇數(shù)為黑</p><p><b>  {</b></p><p>  lblBla

107、ck.Visible = false;</p><p>  lblWhite.Visible = true;</p><p>  pictureBox1.Image = imageList1.Images[0];</p><p>  clientRole.SendMessage("Down#" + s.ToString() + "|&q

108、uot; + "0" + "@" + BBow.ToString());</p><p>  forChess[s] = 0;</p><p><b>  }</b></p><p>  else //white</p><p><b>  {</b><

109、/p><p>  lblBlack.Visible = true;</p><p>  lblWhite.Visible = false;</p><p>  pictureBox1.Image = imageList1.Images[1];</p><p>  clientRole.SendMessage("Down#" +

110、 s.ToString() + "|" + "1" + "@" + BBow.ToString());</p><p>  forChess[s] = 1;</p><p>  } </p><p>  Low.ChessJudge(ref forChess, ref

111、BCount, this);</p><p>  IFirst = false;</p><p><b>  }</b></p><p><b>  else</b></p><p><b>  {</b></p><p>  MessageBox.Sh

112、ow("對(duì)方還沒(méi)下棋!!");</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  else</b></p><p><b>  {</b></p><p>

113、;  MessageBox.Show("請(qǐng)先按準(zhǔn)備和開(kāi)始按鈕!");</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  單例者模式</b></p><p>  private static FrmFi

114、ght frmFight = new FrmFight();</p><p>  public static FrmFight GetInstance()</p><p><b>  {</b></p><p>  if (frmFight.IsDisposed)</p><p><b>  {</b&g

115、t;</p><p>  frmFight = new FrmFight();</p><p><b>  }</b></p><p>  return frmFight;</p><p><b>  }</b></p><p> ?。?). 五子棋規(guī)則示例“從左往右橫向”

116、 </p><p>  for (int k = 0; k < 225; k++)</p><p><b>  {</b></p><p>  if (a[k] == 0)</p><p><b>  {</b></p><p><b>  BCount++;

117、</b></p><p>  for (int p = 1; p < 5; p++)</p><p><b>  {</b></p><p>  if (k + p < ((k / 15) + 1) * x)</p><p><b>  {</b></p>&l

118、t;p>  if (a[k + p] == 0)</p><p><b>  {</b></p><p><b>  BCount++;</b></p><p><b>  }</b></p><p>  else if (a[k + p] == 1)</p>

119、<p><b>  {</b></p><p>  BCount = 0;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</b></p><p>  i

120、f (BCount == 5)</p><p><b>  {</b></p><p>  frmFight.BlackWin();</p><p><b>  return;</b></p><p><b>  }</b></p><p><b&

121、gt;  else</b></p><p><b>  {</b></p><p>  BCount = 0;</p><p><b>  }</b></p><p><b>  }</b></p><p><b>  }</

122、b></p><p><b>  6系統(tǒng)測(cè)試</b></p><p><b>  6.1測(cè)試分析報(bào)告</b></p><p>  系統(tǒng)測(cè)試是保證軟件質(zhì)量的關(guān)鍵,也是在成功開(kāi)發(fā)軟件系統(tǒng)的重要保證之一。它貫穿于軟件系統(tǒng)開(kāi)發(fā)的整個(gè)過(guò)程中,具有多種系統(tǒng)測(cè)試方式和測(cè)試對(duì)象。</p><p>  6.2.

123、1測(cè)試方式簡(jiǎn)介</p><p>  單元測(cè)試:對(duì)每個(gè)模塊進(jìn)行單獨(dú)測(cè)試,最大程度的減少模塊內(nèi)部所有錯(cuò)誤。</p><p>  組合測(cè)試采:用自頂向下測(cè)試方法對(duì)通過(guò)單元測(cè)試的模塊進(jìn)行系統(tǒng)化的方法裝配與測(cè)試軟件系統(tǒng)。</p><p>  系統(tǒng)測(cè)試:系統(tǒng)集成后,對(duì)其整體性進(jìn)行測(cè)試,對(duì)各模塊之間的數(shù)據(jù)通信和數(shù)據(jù)共享進(jìn)行測(cè)試,保證系統(tǒng)運(yùn)行的正確性。</p><

124、;p><b>  6.2改進(jìn)意見(jiàn)</b></p><p>  由于時(shí)間倉(cāng)促與測(cè)試不方便,對(duì)戰(zhàn)時(shí)一次只能與一位玩家對(duì)戰(zhàn),并且在網(wǎng)絡(luò)上發(fā)送的信息都采用明文發(fā)送,這其實(shí)是很不安全的。若要實(shí)現(xiàn)一次能與多個(gè)玩家對(duì)戰(zhàn)其實(shí)很簡(jiǎn)單,只需像本程序中UDP的套接字那樣封裝到一個(gè)類中,然后當(dāng)監(jiān)聽(tīng)到某個(gè)網(wǎng)絡(luò)端點(diǎn)的連接后,將Accept()產(chǎn)生的套接字放到一個(gè)以此網(wǎng)絡(luò)端點(diǎn)為Key的Dictionary中。信息的

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 眾賞文庫(kù)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論