版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
PAGEword文檔可自由復(fù)制編輯word文檔可自由復(fù)制編輯1.引言1.1游戲介紹連連看來(lái)源于街機(jī)游戲《四川麻將》和《中國(guó)龍》,是給一堆圖案中的相同圖案進(jìn)行配對(duì)的簡(jiǎn)單游戲,在2003年,一個(gè)叫做朱俊的網(wǎng)友將這種形式搬到了PC上,立刻成為辦公一族的新寵,并迅速傳遍了世界各地。飽受工作壓力的人們沒(méi)有太多的時(shí)間進(jìn)行復(fù)雜的游戲,而對(duì)于這種動(dòng)動(dòng)鼠標(biāo)就能過(guò)關(guān)的游戲情有獨(dú)鐘。之后村子的連連看風(fēng)靡版,阿達(dá)的連連看奧運(yùn)版,連連看反恐版,還有敏敏連連看,水晶連連看等遍地開(kāi)花,造就了一個(gè)連連看的新世界。連連看游戲有多種地圖樣式和道具系統(tǒng)、大大加強(qiáng)了游戲的可玩性,是一款老少皆宜的休閑佳品。1.2目的網(wǎng)絡(luò)小游戲制作的目的是滿足了人們休閑的需要,在緊張工作之余休閑類的小游戲能夠給人帶來(lái)最大程度的放松,也可以增進(jìn)人們之間的交流,溝通,通過(guò)游戲還可以認(rèn)識(shí)更多的朋友,也可以到達(dá)跨省、跨市,甚至跨國(guó)間人們互相娛樂(lè)的目的。另外也通過(guò)本程序?qū)⑷陙?lái)所學(xué)的專業(yè)知識(shí)和其他方面的知識(shí)融入到實(shí)際應(yīng)用中。1.3主要問(wèn)題開(kāi)始制作游戲時(shí),主要要解決的問(wèn)題有以下幾個(gè)方面:如何設(shè)置整個(gè)游戲的界面;如何控制連連看游戲中隨機(jī)圖片的生成且每種圖片必須為偶數(shù)個(gè);游戲開(kāi)始后,判斷鼠標(biāo)兩次點(diǎn)擊的圖片能否消去,即圖片是否相同且圖片之間路徑的判斷.1.4開(kāi)發(fā)環(huán)境 Intel?Pentium?42.0GHz,512M內(nèi)存,80G硬盤 Microsoft?Windows?2000Professional Microsoft?VisualC++6.02.需求分析關(guān)于連連看的功能描述如下:運(yùn)行游戲并進(jìn)行初始化工作,將整個(gè)游戲區(qū)域分成縱向和橫向擴(kuò)展的若干個(gè)小方塊,并且這些小方塊是由多種動(dòng)物圖案成對(duì)地分布于游戲區(qū)域的不同位置。玩家可以通過(guò)選取相同的兩個(gè)物件來(lái)對(duì)它們進(jìn)行消除的操作,直到將游戲區(qū)域中的所有方塊對(duì)都被消除后為勝利。游戲的整體運(yùn)行效果如圖1.1。圖1.13.功能模塊的設(shè)計(jì)3.功能模塊的設(shè)計(jì)3.1類設(shè)計(jì)這個(gè)游戲的主要類是游戲模式類,類名為CMyDlg。這個(gè)類主要對(duì)包括圖案方塊的銷毀判斷,游戲勝利判斷以及整個(gè)游戲用戶交換功能的實(shí)現(xiàn)。它uml圖如下:CMyDlgm_mem3DBkDC:CDCm_mem3DBkBmp:CBitmapm_memAnimalDC:CDC m_memAnimalBmp:CBitmapm_MemDC:CDC m_memBitmap:CBitmapm_map:intm_nRow: int m_nCol:int m_nX1:int m_nY1:int GameDraw(CDC*pDC):voidStartNewGame():voidPreTranslateMessage(MSG*pMsg):BOOLIsLink(intx1,inty1,intx2,inty2):BOOLIsWin(void):BOOLX1_Link_X2(intx,inty1,inty2):BOOLY1_Link_Y2(intx1,intx2,inty):BOOLOneCornerLink(intx1,inty1,intx2,inty2):BOOLTwoCornerLink(intx1,inty1,intx2,inty2):BOOLYThrough(intx,inty,BOOLbAdd):BOOLXThrough(intx,inty,BOOLbAdd):BOOLLineX(intx,inty1,inty2):BOOLLineY(intx1,intx2,inty):BOOL這些成員函數(shù)和成員變量的算法分析與設(shè)計(jì)以及核心算法中有詳細(xì)介紹。3.2.框架的搭建從圖1.1可以看出,整個(gè)運(yùn)行的界面由菜單欄和游戲區(qū)域的圖形顯示組成,因此,需要用對(duì)話框模板的方式去搭建整個(gè)框架再添加一個(gè)菜單欄。首先,創(chuàng)建一個(gè)基于對(duì)話框模板的項(xiàng)目,如圖1.2所示。圖1.2在創(chuàng)建過(guò)程的第一步“MFC應(yīng)用程序向?qū)А襟E1”中應(yīng)該選擇“基本對(duì)話框”選項(xiàng),確保應(yīng)用程序的創(chuàng)建是對(duì)話框模板,如圖1.3所示。圖1.3然后添加菜單欄為對(duì)話框增加菜單欄并為對(duì)話框創(chuàng)建一個(gè)菜單資源IDR_MENU1。圖1.4在對(duì)話框的屬性對(duì)話框中在Menu屬性中選擇剛創(chuàng)建的菜單資源IDR_MENU1。此時(shí)保存編譯后,在對(duì)話框中就可看到菜單。圖1.5點(diǎn)擊快捷鍵Ctrl+W,在“AddaClass”對(duì)話框中選擇已存在的對(duì)話框類“Selectanexistingclass”,打開(kāi)“SelectClass”對(duì)話框。圖1.6選擇對(duì)話框類,本例中的類名為CMyDlg,選中進(jìn)入下一步。圖1.7進(jìn)入MFCClassWizard對(duì)話框,在消息映射屬性頁(yè)中,為菜單增加消息處理函數(shù),為子菜單增加COMMAND處理函數(shù)函數(shù)名為默認(rèn)函數(shù)名。如圖1.8所示:圖1.8給各個(gè)子菜單添加消息映射,同上所述。然后編輯函數(shù)代碼,實(shí)現(xiàn)自己定義的功能,添加的代碼如下:voidCMyDlg::Onexit(){ //TODO:AddyourcommandhandlercodehereCDialog::OnCancel(); }voidCMyDlg::Onnewgame(){ //TODO:AddyourcommandhandlercodehereStartNewGame(); }voidCMyDlg::Onathour(){ //TODO:AddyourcommandhandlercodehereMessageBox("11物41陳曉麗"); } voidCMyDlg::Onabout(){ //TODO:AddyourcommandhandlercodehereMessageBox("本游戲連連由C++MFC設(shè)計(jì)實(shí)現(xiàn),是給一堆圖案中的相同圖案進(jìn)行配對(duì)的簡(jiǎn)單游戲"); }編譯運(yùn)行后,點(diǎn)擊各子菜單,將彈出對(duì)話框。4.算法分析與設(shè)計(jì)在對(duì)算法進(jìn)行分析前,應(yīng)先抽象出游戲的基本是具結(jié)構(gòu),而對(duì)連連看游戲來(lái)說(shuō),核心的部分應(yīng)該是整個(gè)游戲區(qū)域的地圖數(shù)據(jù)。那么,下面將分析游戲特性,然后設(shè)計(jì)出標(biāo)識(shí)地圖的數(shù)據(jù)結(jié)構(gòu)。4.1游戲地圖數(shù)據(jù)設(shè)計(jì)對(duì)于整個(gè)游戲區(qū)域,可以把它看作一個(gè)是由若干個(gè)小方塊構(gòu)成的地圖,而且每一個(gè)小方塊放置著不同的動(dòng)物圖案,可將其稱之為圖案小方塊。這些圖案小方塊零散地分布在地圖的不同位置區(qū)域,并且每一個(gè)圖案小方塊都有與其對(duì)應(yīng)的完全一樣的另外一個(gè)小方塊,如圖1.8所示。圖1.9如圖1.9所示,整個(gè)游戲游戲區(qū)域被抽象成一個(gè)有坐標(biāo)位置屬性的平面,平面上零散地分布著若干個(gè)小方塊,并且這些小方塊的物種起碼是成對(duì)出現(xiàn)的。經(jīng)過(guò)前面的描述和分析后,可以把游戲區(qū)域地圖用一個(gè)數(shù)組m_map來(lái)表示。m_map是把地圖設(shè)計(jì)成一個(gè)動(dòng)態(tài)分配的int整形一維數(shù)組,對(duì)地圖中的行列數(shù)的表達(dá),用一個(gè)轉(zhuǎn)換法則即可??梢栽贑MyDlg類對(duì)象定義中添加地圖核心數(shù)據(jù)的成員變量,具體如下://地圖位置相關(guān)屬性組 int*m_map;//動(dòng)態(tài)地圖數(shù)據(jù)頭指針(一維數(shù)組) int m_nRow; //地圖的行數(shù)(虛擬) int m_nCol; //地圖的列數(shù)(虛擬)上面的成員變量中定義了一個(gè)整形指針標(biāo)量m_map,用于記錄動(dòng)態(tài)分配出來(lái)的一維數(shù)組地圖空間的首地址。對(duì)于地圖區(qū)域中的某個(gè)小方塊的類型,可以用一個(gè)整形的ID來(lái)進(jìn)行識(shí)別。這里為標(biāo)識(shí)地圖的行列位置分別添加m_nRow和m_nCol變量?,F(xiàn)在,地圖的數(shù)據(jù)結(jié)構(gòu)已經(jīng)設(shè)計(jì)好。下面對(duì)游戲進(jìn)行初始化。由于方塊需要成對(duì)地出現(xiàn),因此在做地圖的初始化時(shí),不僅僅是對(duì)動(dòng)物種類做簡(jiǎn)單的隨機(jī)取數(shù),然后將該隨機(jī)選取出來(lái)的物件放到地圖區(qū)域中去就了事,而是需要成對(duì)地對(duì)物種進(jìn)行成對(duì)選取,就是說(shuō)地圖中的小方塊必須是偶數(shù)個(gè)。前面提到過(guò),把地圖數(shù)組設(shè)置成動(dòng)態(tài)分配方式,目的是讓其數(shù)據(jù)空間可以根據(jù)行列數(shù)的需求動(dòng)態(tài)地獲取,而對(duì)于實(shí)際不同大小比例的地圖可以預(yù)先定義幾組關(guān)于行列數(shù)的宏來(lái)實(shí)現(xiàn)。當(dāng)需要?jiǎng)?chuàng)建時(shí),根據(jù)宏值的不同分配不同大小的地圖空間即可。接下來(lái)在CMyDlg類的構(gòu)造函數(shù)對(duì)地圖數(shù)據(jù)進(jìn)行相關(guān)的初始化:#defineROWCOUNT7 //行數(shù)#defineCOLCOUNT12 //列數(shù)CMyDlg::CMyDlg(CWnd*pParent/*=NULL*/) :CDialog(CMyDlg::IDD,pParent){ …… //記錄方塊置為無(wú)效狀態(tài) m_nY1=BLANK_STATE; m_nX1=BLANK_STATE; //初始化行列數(shù) m_nRow=ROWCOUNT; m_nCol=COLCOUNT; //根據(jù)行列數(shù)動(dòng)態(tài)分配內(nèi)核數(shù)據(jù)數(shù)組空間 m_map=newint[m_nRow*m_nCol];}CMyDlg::~CMyDlg(){ //釋放動(dòng)態(tài)數(shù)組空間 delete[]m_map;}在CMyDlg類對(duì)象的實(shí)現(xiàn)中,定義了一些關(guān)于地圖行列數(shù)的宏,如ROWCOUNT和COLCOUNT,并且在CMyDlg類對(duì)象的構(gòu)造函數(shù)中,進(jìn)行了行列的真實(shí)確認(rèn)賦值,并根據(jù)當(dāng)前行列數(shù)的大小對(duì)地圖數(shù)據(jù)空間進(jìn)行動(dòng)態(tài)創(chuàng)建。因?yàn)榈貓D數(shù)據(jù)是用new在堆棧動(dòng)態(tài)創(chuàng)建的,所以在銷毀該對(duì)象時(shí)要將這些內(nèi)存空間釋放,如代碼所示在CMyDlg類對(duì)象的析構(gòu)函數(shù)中調(diào)用delete將m_map指向的所有空間都釋放掉。4.2數(shù)據(jù)的初始化工作接下來(lái),再分配好的空間中放上適當(dāng)?shù)膱D案方塊物件,對(duì)數(shù)據(jù)進(jìn)行初始化。即需要對(duì)地圖空間內(nèi)的數(shù)據(jù)進(jìn)行成對(duì)性的隨機(jī)布局,因此可以將該功能的實(shí)現(xiàn)封裝在StartNewGame()函數(shù)里面,其代碼如下:voidCMyDlg::StartNewGame(){ //初始化地圖,將地圖中所有方塊區(qū)域位置置為空方塊狀態(tài) for(intiNum=0;iNum<(m_nCol*m_nRow);iNum++) { m_map[iNum]=BLANK_STATE; } //部下隨機(jī)種子 srand(time(NULL)); //生成隨機(jī)地圖 //將所有匹配成對(duì)的動(dòng)物物種放進(jìn)一個(gè)臨時(shí)的地圖中 CDWordArraytmpMap; for(inti=0;i<(m_nCol*m_nRow)/6;i++) for(intj=0;j<6;j++) tmpMap.Add(i); //每次從上面的臨時(shí)地圖中取走(獲取后并在臨時(shí)地圖刪除) //一個(gè)動(dòng)物放到地圖的空方塊上 for(i=0;i<m_nRow*m_nCol;i++) { //隨機(jī)挑選一個(gè)位置 intnIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize(); //獲取該選定物件放到地圖的空方塊 m_map[i]=tmpMap.GetAt(nIndex); //在臨時(shí)地圖除去該動(dòng)物 tmpMap.RemoveAt(nIndex); } //更新顯示 Invalidate(TRUE);}在游戲進(jìn)行初始化的過(guò)程中,應(yīng)該先對(duì)整個(gè)地圖中的各個(gè)區(qū)域做必要的初始化操作,將它們的狀態(tài)設(shè)置為BLANK_START空白方塊狀態(tài)(無(wú)動(dòng)物圖案方塊),關(guān)于BLANK_START空白方塊狀態(tài)的定義,跟其他動(dòng)物方塊的物種定義表達(dá)類似,也是用整數(shù)ID來(lái)對(duì)它進(jìn)行標(biāo)識(shí),不過(guò)不同的是,由于他代表該方塊區(qū)域無(wú)圖案,所以這里用-1的宏值來(lái)表示,具體定義如下:#defineBLANK_STATE-1//空方塊(沒(méi)有任何動(dòng)物)可以看到,對(duì)圖案方塊的布局,先用srand()函數(shù)對(duì)時(shí)間函數(shù)布下隨機(jī)種子,然后調(diào)用rand()函數(shù)對(duì)具體的圖案方塊的種類進(jìn)行隨機(jī)的獲取。在這里需要引入一個(gè)臨時(shí)地圖tmpMap,該臨時(shí)地圖的大小與內(nèi)核數(shù)據(jù)地圖的大小一致,并且先添置好4組完全一樣的圖案類型ID數(shù)據(jù)(0~(m_nCol*m_nRow)/4),然后再將已經(jīng)安放在tmpMap中的圖案作隨機(jī)抽取,并放到內(nèi)核地圖數(shù)據(jù)中去,將取出的元素從tmpMap中除去。4.3快捷方式的創(chuàng)建按Ctrl+W為類添加消息映射PreTranslateMessage,雙擊函數(shù)名為該函數(shù)添加如下代碼BOOLCMyDlg::PreTranslateMessage(MSG*pMsg){ //TODO:Addyourspecializedcodehereand/orcallthebaseclass if(pMsg->message==WM_KEYDOWN) { if(pMsg->wParam==VK_F2) { StartNewGame(); }if(pMsg->wParam==VK_F3) {CDialog::OnCancel(); } }在運(yùn)行游戲時(shí)按下F2便可重新開(kāi)始新游戲,按F3便可退出游戲。5.核心算法在完成地圖數(shù)據(jù)設(shè)計(jì)后,就開(kāi)始展開(kāi)游戲核心的設(shè)計(jì),該部分主要包括圖案方塊的銷毀判斷,游戲勝利判斷以及整個(gè)游戲用戶交換功能的實(shí)現(xiàn)。5.1圖案方塊的連接判斷對(duì)于選中的兩個(gè)方塊的銷毀,他們必須符合下面3個(gè)條件:(1)選中的兩個(gè)方塊圖案相同。(2)選中的兩個(gè)方塊之間沒(méi)有障礙物阻礙的情況下,可以用若干個(gè)垂直的直線線段連接起來(lái)。(3)這些將它們連接起來(lái)的直線線段的折點(diǎn)不超過(guò)兩個(gè)(連接線由x軸和y軸的平行線組成)?,F(xiàn)在針對(duì)(2)和(3)進(jìn)行分析,同種物件的連接方式大致可以分成以下3種:直接方式有一個(gè)折點(diǎn)的垂直線段連接。有兩個(gè)折點(diǎn)的垂直線段連接.。1.直接連接方式在直接連接方式中,必須要求所選定的兩個(gè)方塊在同一水平直線上(可以為x方向或y方向),并且兩個(gè)方塊之間沒(méi)有任何其他圖案方塊。2.一個(gè)這點(diǎn)連接方式所選定的兩個(gè)方塊如果通過(guò)折點(diǎn)的方式連接,那么對(duì)于折點(diǎn)來(lái)說(shuō),每個(gè)折點(diǎn)必定有且至少有一個(gè)坐標(biāo)(x或y)是和其中一個(gè)目標(biāo)點(diǎn)相同的,即折點(diǎn)必定在兩個(gè)目標(biāo)點(diǎn)所在的x方向或y方向的直線上。此外,對(duì)于一個(gè)折點(diǎn)連接的情況,折點(diǎn)應(yīng)該為第一個(gè)選中方塊的橫向線或縱向線與第二個(gè)選中方塊的縱向線和橫向線相交而得出。3.兩個(gè)折點(diǎn)的連接方式這種方式的兩個(gè)折點(diǎn)所連成的直線與兩物件的直接連線可以構(gòu)成平行線,因此可以根據(jù)這個(gè)規(guī)律,將這條水平線在游戲區(qū)域允許的條件上下移動(dòng),然后通過(guò)判斷整條帶垂直折線點(diǎn)的曲線之間有無(wú)障礙物方式來(lái)確定是否可以連同。這種情況可以分為兩種情況:(1)選中的兩圖案方塊在同一直線,兩折點(diǎn)間的直連線可在其這兩個(gè)方塊之間的空間位置作移動(dòng),其約束是不超過(guò)游戲邊界區(qū)域。(2)選中的兩圖案方塊不在同一直線,兩折點(diǎn)間的直連線可在兩個(gè)方塊之間的空間位置作移動(dòng),其約束是兩方塊之間的區(qū)域。經(jīng)過(guò)上面詳細(xì)的分析后,可以對(duì)選定的兩方塊是否可以作抵消操作可以這樣設(shè)計(jì)下去。首先,對(duì)簡(jiǎn)單的直接連情況進(jìn)行判斷,看其是否符合條件,假如不能,再加深一個(gè)級(jí)別的復(fù)雜度,對(duì)一個(gè)折點(diǎn)的情況進(jìn)行判斷,依次類推,如下圖所示。圖1.10圖1.11根據(jù)如圖1.6所示的流程圖,可以對(duì)選定的兩個(gè)方塊(分別在(x1,y1)以及(x2,y2)兩個(gè)區(qū)域位置,其中x,y分別代表行與列的概念)是否可以抵消作以下實(shí)現(xiàn)。把該功能封裝在IsLink()函數(shù)里面,其代碼如下所示://判斷選中的兩個(gè)方塊是否可以消除BOOLCMyDlg::IsLink(intx1,inty1,intx2,inty2){ //X直連方式 if(x1==x2) { if(X1_Link_X2(x1,y1,y2)) returnTRUE; } //Y直連方式 elseif(y1==y2) { if(Y1_Link_Y2(x1,x2,y1)) returnTRUE; } //一個(gè)轉(zhuǎn)彎直角的聯(lián)通方式 if(OneCornerLink(x1,y1,x2,y2)) { returnTRUE; } //兩個(gè)轉(zhuǎn)彎直角的聯(lián)通方式 elseif(TwoCornerLink(x1,y1,x2,y2)) { returnTRUE; } returnFALSE;}在上面的實(shí)現(xiàn)中,先是對(duì)直連方式中的x方向直連Y1_Link_Y2()以及y方向直連X1_Link_X2()這兩種情況進(jìn)行判斷,如果尚未取得結(jié)果,再通過(guò)調(diào)用OneCornerLink()函數(shù)對(duì)一個(gè)折點(diǎn)的情況進(jìn)行判斷,或者更糟糕的時(shí)候調(diào)用TwoCornerLink()函數(shù)對(duì)兩個(gè)這點(diǎn)的情況進(jìn)行判斷,然后得出最終結(jié)果。下面將對(duì)上面涉及到的子功能模塊進(jìn)行實(shí)現(xiàn),代碼如下所示://X直接連通BOOLCMyDlg::X1_Link_X2(intx,inty1,inty2){ //保證y1的值小于y2 if(y1>y2) { //數(shù)據(jù)交換 intn=y1; y1=y2; y2=n; } //直通 for(inti=y1+1;i<=y2;i++) { if(i==y2) returnTRUE; if(m_map[i*m_nCol+x]!=BLANK_STATE) break; } //左通 if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE)) returnTRUE; //右通 if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE)) returnTRUE; returnFALSE;}//Y直接連通BOOLCMyDlg::Y1_Link_Y2(intx1,intx2,inty){ if(x1>x2) { intx=x1; x1=x2; x2=x; } //直通 for(inti=x1+1;i<=x2;i++) { if(i==x2) returnTRUE; if(m_map[y*m_nCol+i]!=BLANK_STATE) break; } //上通 if(YThrough(x1,y-1,FALSE)&&YThrough(x2,y-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y+1,TRUE)&&YThrough(x2,y+1,TRUE)) returnTRUE; returnFALSE;}//是否同一直線通//BOOLCMyDlg::LineX(intx,inty1,inty2){ if(y1>y2) { inty=y1; y1=y2; y2=y; } for(inty=y1;y<=y2;y++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(y==y2) returnTRUE; } returnFALSE;}////是否同一直線通//BOOLCMyDlg::LineY(intx1,intx2,inty){ if(x1>x2) { intx=x1; x1=x2; x2=x; } for(intx=x1;x<=x2;x++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(x==x2) returnTRUE; } returnFALSE;}//1直角接口連通BOOLCMyDlg::OneCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } if(y2<y1) { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1)) returnTRUE; returnFALSE; } else { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1)) returnTRUE; returnFALSE; } returnFALSE;}//2直角接口連通BOOLCMyDlg::TwoCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } //右通 if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE)) returnTRUE; //左通 if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE)) returnTRUE; //上通 if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE)) returnTRUE; //右 for(intx=x1+1;x<m_nCol;x++) { if(m_map[y1*m_nCol+x]>-1) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //左 for(x=x1-1;x>-1;x--) { if(m_map[y1*m_nCol+x]!=BLANK_STATE) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //上 for(inty=y1-1;y>-1;y--) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } //下 for(y=y1+1;y<m_nRow;y++) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } returnFALSE;}BOOLCMyDlg::XThrough(intx,inty,BOOLbAdd){ if(bAdd) { for(inti=x;i<m_nCol;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=x;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::YThrough(intx,inty,BOOLbAdd){ if(bAdd) { for(inti=y;i<m_nRow;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=y;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } returnTRUE;}這里把直接連接方式分為直通,左通,右通3種情況,如1.12圖所示。下面簡(jiǎn)單介紹直通和左通兩種情況(右通與左通類似)(1)直通:直通就是在選定的兩個(gè)方塊直連線中,沒(méi)有被任何方塊所阻礙。(2)左通:左通就是選定的兩個(gè)方塊的直連線之間有其他方塊阻礙,但是通過(guò)它的左側(cè)可以將它們無(wú)阻礙地連通。直連方式中的此種情況跟前面分析的兩個(gè)折點(diǎn)連接方式中的其中一點(diǎn)相當(dāng)類似,如1.13圖所示。它們之間的區(qū)別就是,左通的連接線直接在其相鄰的位置連通,從而不構(gòu)成垂直折點(diǎn)的效果,而兩個(gè)折點(diǎn)連同方式中的其中一個(gè)類似的情況是,線的連通起碼要偏移一個(gè)方塊的距離來(lái)形成連通。圖1.12圖1.13同理,有上通和下通,它們的情況與左通和右通類似。5.2游戲勝利的判斷要判斷游戲的勝利,實(shí)現(xiàn)起來(lái)比較簡(jiǎn)單,只需對(duì)地圖中的所有區(qū)域的狀態(tài)進(jìn)行檢測(cè)就可里了,只要檢測(cè)到地圖中有一個(gè)圖案方塊還沒(méi)有被抵消,則證明游戲沒(méi)有結(jié)束,完成判斷。其代碼如下所示://檢測(cè)是否已經(jīng)贏得了游戲BOOLCMyDlg::IsWin(void){ //檢測(cè)所有是否尚有非未被消除的方塊 //(非BLANK_STATE狀態(tài)) for(inti=0;i<m_nRow*m_nCol;i++) { if(m_map[i]!=BLANK_STATE) { returnFALSE; } } returnTRUE;}游戲勝利界面如圖1.14所示圖1.14游戲勝利界面至此,已經(jīng)完成整個(gè)游戲基本的內(nèi)部相關(guān)功能模塊的運(yùn)算,接下來(lái)實(shí)現(xiàn)用戶的交互部分的功能。5.3鼠標(biāo)交互功能的實(shí)現(xiàn)對(duì)于用戶交互的實(shí)現(xiàn),這里選擇鼠標(biāo)交互方式。下面簡(jiǎn)單描述一下通過(guò)鼠標(biāo)交互方式實(shí)現(xiàn)的功能。鼠標(biāo)選取兩個(gè)圖案方塊后,程序?qū)⒆詣?dòng)判斷所選定的兩個(gè)方塊是否能進(jìn)行抵消操作,能則進(jìn)行抵消操作。在游戲過(guò)程中,我們不斷重復(fù)上面描述的功能,直到游戲的勝利結(jié)束。下面將鼠標(biāo)事件處理工作歸納為如圖1.14所示的流程。圖1.15對(duì)于鼠標(biāo)交互功能的實(shí)現(xiàn),可以通過(guò)ClassWizard對(duì)鼠標(biāo)左鍵被按下時(shí)觸發(fā)的命令消息WM_LBUTTONDOWN進(jìn)行攔截,并重寫該消息的處理函數(shù)OnLButtonDown(),其程序清單如下所示。voidCMyDlg::OnLButtonDown(UINTnFlags,CPointpoint){ //1.計(jì)算鼠標(biāo)點(diǎn)擊方塊的的位置 intx=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1; inty=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1; //2.在游戲區(qū)域內(nèi)并且該區(qū)域還有該區(qū)域不是空的區(qū)域 if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!=BLANK_STATE) { //3.假設(shè)尚未記錄第一個(gè)方塊 if(m_nX1==BLANK_STATE) { //4.記錄第一個(gè)方塊的位置 m_nX1=x; m_nY1=y; //獲取程序框架的設(shè)備環(huán)境 CDC*pWinDC=GetDC(); //臨時(shí)繪制點(diǎn)中的方塊外框 //只繪屏幕不載入內(nèi)存位圖 CPenmyPen; CPen*pOldPen; myPen.CreatePen(PS_SOLID,4,RGB(255,0,0)); pOldPen= pWinDC->SelectObject(&myPen); //方塊外框繪制,線條環(huán)繞繪制框架 pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->LineTo((x+1)*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,y*FRONTHEIGHT); //現(xiàn)場(chǎng)恢復(fù) pWinDC->SelectObject(pOldPen); } else { //5.判斷是否點(diǎn)擊的方塊非本身,是否點(diǎn)擊同一種動(dòng)物 if((m_nX1!=x||m_nY1!=y)&& m_map[m_nY1*m_nCol+m_nX1]==m_map[y*m_nCol+x] ) { //6.檢測(cè)是否可以消除 if(IsLink(m_nX1,m_nY1,x,y)) { //7.數(shù)據(jù)清理 m_map[m_nY1*m_nCol+m_nX1]=BLANK_STATE; m_map[y*m_nCol+x]=BLANK_STATE; } } //8.清空記錄方塊的值 m_nX1=BLANK_STATE; m_nY1=BLANK_STATE; //通知重繪 Invalidate(FALSE); } } //察看是否已經(jīng)勝利 if(IsWin()) { MessageBox("恭喜您勝利闖關(guān),即將開(kāi)始新局"); StartNewGame(); }}按照預(yù)先設(shè)計(jì)出的鼠標(biāo)事件處理流程,上面已經(jīng)將它轉(zhuǎn)換成具體的實(shí)現(xiàn)代碼。下面將按照流程的子功能模塊的劃分方式,對(duì)整個(gè)功能模塊的具體協(xié)調(diào)和實(shí)現(xiàn)過(guò)程進(jìn)行簡(jiǎn)單的描述。(1)首先,利用鼠標(biāo)的當(dāng)前坐標(biāo)位置point對(duì)每個(gè)小單元方塊的寬度FRONTWIDTH和高度FRONTHEIGHT分別取模,獲取當(dāng)前鼠標(biāo)落點(diǎn)所在的游戲區(qū)域的具體行列數(shù)(x,y)。(2)判斷出該行列數(shù)(x,y)是否符合條件。保證運(yùn)算出來(lái)的行數(shù)x和列數(shù)y的預(yù)定義區(qū)域最大的行數(shù)m_nCol和列數(shù)m_nRow內(nèi),并且點(diǎn)擊的區(qū)域狀態(tài)不是空白方塊區(qū)域BLANK_STATE(3)對(duì)判斷此次鼠標(biāo)書劍的選取是否與第一個(gè)方塊的選取一樣,只需通過(guò)用于記錄第一個(gè)被選中的方塊的行列數(shù)的成員變量m_nX1是否為有效即可。這里將m_nX1以及m_nY1來(lái)記錄它所在的行、列數(shù),并且每次經(jīng)過(guò)判斷后都會(huì)將它們的狀態(tài)恢復(fù)為空白無(wú)選中狀態(tài)BLANK_STATE。關(guān)于這兩個(gè)用作記錄第一個(gè)選中圖案方塊行列數(shù)的成員變量,在對(duì)話框類中的具體定義如下所示: int m_nX1;//鼠標(biāo)選中的記錄方塊列數(shù) int m_nY1; //鼠標(biāo)選中的記錄方塊行數(shù)(4)對(duì)于本次選中的方塊為第一選中的情況,先用m_nX1和m_nY1對(duì)當(dāng)前的選中方塊位置做記錄,然后直接在屏幕的該區(qū)域繪制圖像,為該方塊區(qū)域添加一個(gè)紅色的矩形外邊框,用以提示用戶當(dāng)前的第1個(gè)圖案方塊選中所在的位置。需要注意的是,對(duì)于標(biāo)記方塊的加亮邊框繪制是通過(guò)GetDC()函數(shù)來(lái)獲取對(duì)話框窗體(屏幕)的設(shè)備環(huán)境,對(duì)繪制的圖像數(shù)據(jù)沒(méi)有作歷史記錄的方式來(lái)繪制的。(5)在這一處理中,對(duì)該選定方塊作一些判斷,以便更高效地處理。判斷選中的方塊與前一方塊是否為同一圖案方塊,并且此次選擇不與上一次選定的方塊為同一方塊,然后才跳到下一步對(duì)兩個(gè)選定的方塊是否可以抵消的流程中去。(6)調(diào)用前面已經(jīng)實(shí)現(xiàn)的答功能函數(shù)IsLink()來(lái)判斷當(dāng)前所選定的兩個(gè)圖案方塊是否可以抵消。(7)如果可以抵消,對(duì)選中的兩個(gè)方塊在內(nèi)部核心地圖對(duì)應(yīng)的數(shù)據(jù)狀態(tài)作適當(dāng)?shù)男薷模瑢⑺鼈兊臓顟B(tài)記作已經(jīng)被銷毀的空方塊狀態(tài)BLANK_STATE。(8)完成第二個(gè)圖案的選取與相關(guān)的功能操作后,我們需要前面已經(jīng)選去第1個(gè)方塊位置的記錄作清理工作,以便下一個(gè)新方塊的選擇。(9)最后,判斷此次的鼠標(biāo)操作是否已經(jīng)勝利結(jié)束,如果是則給予用戶提示,然后重新開(kāi)適新的一關(guān)。6.繪圖功能的實(shí)現(xiàn)在完成以上所有的交互以及內(nèi)部數(shù)據(jù)關(guān)聯(lián)的運(yùn)算處理后,最后要將這些數(shù)據(jù)展現(xiàn)到屏幕上。6.1位圖圖像的準(zhǔn)備首先,準(zhǔn)備好一個(gè)帶有不同動(dòng)物種以及一個(gè)3D邊框效果的位圖,如圖1.15所示。通過(guò)資源編輯器將它們引入到項(xiàng)目中來(lái),并將它們的ID分別命名為IDB_BMP_ANIMAL和IDB_BITMAP_3DFRAMES。圖1.16word文檔可自由復(fù)制編輯6.2繪圖方案的設(shè)計(jì)對(duì)于游戲的繪制實(shí)現(xiàn),這里采用內(nèi)存位圖映射的方式,先將整個(gè)游戲區(qū)域的圖像繪制到內(nèi)存位圖中,然后再一次性地將它拷貝到屏幕上予以顯示,如圖1.16所示圖1.176.3繪圖資源的載入與初始化根據(jù)圖1.16所示的描述方案,可以在內(nèi)存創(chuàng)建兩個(gè)內(nèi)存位圖,并對(duì)它們的圖像進(jìn)行載入。在需要使用的時(shí)候,則可以從這些內(nèi)存位圖中直接去拷貝,并繪制到游戲區(qū)域內(nèi)存位圖中去,接下來(lái)添加關(guān)于繪圖的成員變量,如下所示。//內(nèi)存位圖屬性組 CDC m_mem3DBkDC;//3D框架的內(nèi)存設(shè)備環(huán)境 CBitmapm_mem3DBkBmp;//3D框架的內(nèi)存位圖 CDC m_memAnimalDC;//動(dòng)物圖像的內(nèi)存設(shè)備環(huán)境 CBitmapm_memAnimalBmp;//動(dòng)物圖像的內(nèi)存位圖 CDC m_MemDC;//游戲區(qū)域內(nèi)存設(shè)備環(huán)境 CBitmapm_memBitmap;//游戲區(qū)域內(nèi)存位圖這里,對(duì)3D框架位圖以及動(dòng)物圖案位圖分別創(chuàng)建了對(duì)應(yīng)的設(shè)備環(huán)境m_mem3DBkDC和m_memAnimalDC,并且位它們分配了關(guān)聯(lián)的內(nèi)存位圖變量m_mem3DBkBmp和m_memAnimalBmp。而對(duì)于游戲區(qū)域的內(nèi)存繪制,亦為它創(chuàng)建了一個(gè)內(nèi)存設(shè)備環(huán)境m_MemDC以及關(guān)聯(lián)的內(nèi)存位圖m_memBitmap。在完成以上工作后,需要在程序開(kāi)始運(yùn)行的時(shí)候,一次行對(duì)它們進(jìn)行適當(dāng)?shù)某跏蓟???梢詫⑦@些繪圖的具體初始化加載在CMyDlg對(duì)話框類的初始話函數(shù)OnInitDialog中,代碼如下所示。 //獲取程序框架的設(shè)備環(huán)境 CDC*pWinDC=GetDC(); //內(nèi)存設(shè)備環(huán)境以及內(nèi)存位圖的創(chuàng)建,初始化,關(guān)聯(lián) //3D方塊邊框圖樣內(nèi)存位圖 m_mem3DBkDC.CreateCompatibleDC(pWinDC); m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES); m_mem3DBkDC.SelectObject(&m_mem3DBkBmp); //動(dòng)物圖樣內(nèi)存位圖 m_memAnimalDC.CreateCompatibleDC(pWinDC); m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL); m_memAnimalDC.SelectObject(&m_memAnimalBmp); //整個(gè)游戲區(qū)域內(nèi)存位圖 m_MemDC.CreateCompatibleDC(pWinDC); m_memBitmap.CreateCompatibleBitmap(pWinDC, m_nCol*FRONTWIDTH+5, m_nRow*FRONTHEIGHT+5); m_MemDC.SelectObject(&m_memBitmap); //開(kāi)始一個(gè)新的游戲 StartNewGame(); //放在最桌面的前面顯示 HWNDhWnd=::AfxGetMainWnd()->m_hWnd; ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); //Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE); //Setbigicon SetIcon(m_hIcon,FALSE); //Setsmallicon //TODO:Addextrainitializationhere returnTRUE;//returnTRUEunlessyousetthefocustoacontrol在上面的代碼中,現(xiàn)獲取該程序的屏幕設(shè)備環(huán)境,然后在將前面提到的3個(gè)內(nèi)存設(shè)備環(huán)境以及關(guān)聯(lián)的內(nèi)存位圖與該屏幕設(shè)備環(huán)境兼容,而對(duì)于兩個(gè)用于存儲(chǔ)外部位圖圖像的內(nèi)存位圖,則調(diào)用LoadBitmap()函數(shù)對(duì)他們相應(yīng)的位圖資源進(jìn)行載入以及相關(guān)的初始化工作。6.4游戲區(qū)域的繪制在完成繪圖物件的初始化工作后,接下來(lái)就可以對(duì)整個(gè)游戲區(qū)域的繪制進(jìn)行實(shí)現(xiàn),對(duì)整個(gè)游戲區(qū)域的繪制,可以將封裝在GameDraw()函數(shù)里,其代碼清單如下所示。voidCMyDlg::GameDraw(CDC*pDC){ //繪制背景顏色pDC->FillSolidRect(0,0,m_nCol*FRONTWIDTH+5,m_nRow*FRONTHEIGHT+5,BKCOLOR); for(inti=0;i<m_nRow;i++) { for(intj=0;j<m_nCol;j++) { if(m_map[i*m_nCol+j]==BLANK_STATE) { continue; } //繪制方塊邊框 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, BKWIDTH,BKHEIGHT, &m_mem3DBkDC, 0,BKHEIGHT, SRCCOPY); //繪制方塊 //因?yàn)橐沟眯Ч该?,所以由圖樣的底色以及表面兩部分構(gòu)成 pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, FRONTWIDTH-2,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCAND); pDC->BitBlt(j*FRONTWIDTH,i*FRONTHEIGHT, FRONTWIDTH-2,FRONTHEIGHT-12, &m_memAnimalDC, 0,m_map[i*m_nCol+j]*(FRONTHEIGHT-12), SRCPAINT); } }}在上面程序中,先調(diào)用FillSolidRect()函數(shù)來(lái)繪制整個(gè)游戲區(qū)域的背景,在對(duì)游戲區(qū)域中有動(dòng)物圖案的方塊進(jìn)行3D邊框的繪制,繪制的方法示從3D邊框的內(nèi)存位圖中拷貝,然后在根據(jù)內(nèi)核地圖中每一個(gè)方框區(qū)域的圖案物種從動(dòng)物內(nèi)存位圖m_memAnimalBmp中通過(guò)與它關(guān)聯(lián)的m_memAnimalDC進(jìn)行動(dòng)物圖案的拷貝。7.背景音樂(lè)功能的實(shí)現(xiàn)在游戲過(guò)程中,播放背景音樂(lè)這在一定程度上能夠增加用戶對(duì)游戲的沉侵感。對(duì)聲音模塊信息的管理在程序中是通過(guò)API中的PlaySound函數(shù)來(lái)實(shí)現(xiàn)的。首先選擇一段.wav音樂(lè)在ResourceView界面插入WAVE資源并引入該段音樂(lè),并設(shè)置屬性為IDR_WAVE1,在菜單中添加音樂(lè)菜單和子菜單播放與暫停。同上所述,給播放菜單添加消息映射,并添加下列代碼:PlaySound(MAKEINTRESOURCE(IDR_WAVE1),AfxGetResourceHandle(),SND_ASYNC|SND_RESOURCE|SND_NODEFAULT|SND_LOOP);給暫停菜單添加消息映射,并添加下列代碼:PlaySound(NULL,NULL,SND_FILENAME);因?yàn)镻laySound函數(shù)體被編譯到Winmm.lib庫(kù)文件中,點(diǎn)擊工程—設(shè)置,選擇連接,在對(duì)象/庫(kù)模塊填入winmm.lib,這樣就可在點(diǎn)擊播放菜單播放背景音樂(lè),點(diǎn)擊暫停菜單停止背景音樂(lè)了。8.總結(jié)經(jīng)過(guò)一個(gè)學(xué)期對(duì)《C++實(shí)用教程》的學(xué)習(xí),我學(xué)習(xí)到了基本的理論知識(shí),了解到了C++語(yǔ)言程序設(shè)計(jì)的思想,這些知識(shí)都為我的課程實(shí)踐和進(jìn)一步的學(xué)習(xí)打下了堅(jiān)實(shí)的基礎(chǔ)。在為期近兩周的C++課程設(shè)計(jì)中,我體會(huì)頗多,學(xué)到了很多東西。我加強(qiáng)了對(duì)C++程序設(shè)計(jì)這門課程的認(rèn)識(shí),并且復(fù)習(xí)了自己以前學(xué)習(xí)到的知識(shí)。這些都使得我對(duì)計(jì)算機(jī)語(yǔ)言的學(xué)習(xí)有了更深入的認(rèn)識(shí)!總之,通過(guò)這次課程設(shè)計(jì),我收獲頗豐,相信會(huì)為自己以后的學(xué)習(xí)和工作帶來(lái)很大的好處。像小游戲程序設(shè)計(jì),經(jīng)歷了平時(shí)在課堂和考試中不會(huì)出現(xiàn)的問(wèn)題和考驗(yàn)。而這些問(wèn)題,這并不是我們平時(shí)只靠課本,就可以輕易解決的。所以,鍛煉了我們挑戰(zhàn)難題,學(xué)會(huì)用已掌握的知識(shí)去解決具體問(wèn)題的能力,進(jìn)一步培養(yǎng)了獨(dú)思考問(wèn)題和解決問(wèn)題的能力。特別是學(xué)會(huì)了在Visual
C++中如何調(diào)試程序的方法。當(dāng)然,老師的指導(dǎo)和同學(xué)的幫助也是不可忽視的,他們給了我許多提示和幫助,教會(huì)了我編譯復(fù)雜程序的方法。本文用visualc++來(lái)設(shè)計(jì)與實(shí)現(xiàn)簡(jiǎn)單的連連看游戲的基本功能,對(duì)該游戲的算法以及游戲圖案的繪制進(jìn)行詳細(xì)的介紹,其中核心內(nèi)容包括圖案方塊的銷毀判斷,游戲勝利判斷以及整個(gè)游戲用戶交換功能的實(shí)現(xiàn)。在制作過(guò)程中學(xué)會(huì)了位圖的引入,對(duì)話框背景的設(shè)置,背景音樂(lè)的播放,對(duì)話框顯示菜單的方法等,還加深了對(duì)MFC功能的理解,對(duì)各個(gè)類的函數(shù)功能的理解,對(duì)事件的消息映射的理解。此課程設(shè)計(jì)算法比較簡(jiǎn)單,運(yùn)行速度快。參考文獻(xiàn)1.GeorgeShepherd/DavidKruglinski著,潘愛(ài)民譯Microsoft?VisualC++.NET技術(shù)內(nèi)幕(第6版),,清華大學(xué)出版社,2.楊永國(guó)編,VisualC++6.0實(shí)用教程.清華大學(xué)出版社,20043.唐俊明編,VisualC++6.0編程實(shí)例與技巧.高等教育出版,20024.潘錦平編,軟件系統(tǒng)開(kāi)發(fā)技術(shù).西安電子科技大學(xué)出版社,19975.朱繼滿等譯.,ProgrammingMicrosoftVisualC++技術(shù)內(nèi)幕(第五版),北京希望電子出版社,20016.宋坤等編,VisualC++開(kāi)發(fā)技術(shù)大全,人民郵電出版社,20077.ErichGamma等著,李英軍等譯,機(jī)械工業(yè)出版社,設(shè)計(jì)模式——可復(fù)用面向?qū)ο筌浖幕A(chǔ)8.嚴(yán)蔚敏等編,數(shù)據(jù)結(jié)構(gòu),清華大學(xué)出版社,20069.JohnE.Swanke著,VisualMFC編程實(shí)例,機(jī)械工業(yè)出版社,200010.侯俊杰編著,深入淺出MFC,華中科技大學(xué)出版社11.ABeginner'sGuidetoPointers,AndrewPeace/cpp/pointers.asp附錄:源代碼//課程設(shè)計(jì)(連連看)Dlg.cpp:implementationfile//#include"stdafx.h"#include"課程設(shè)計(jì)(連連看).h"#include"課程設(shè)計(jì)(連連看)Dlg.h"#include"mmsystem.h"#ifdef_DEBUG#definenewDEBUG_NEW#undefTHIS_FILEstaticcharTHIS_FILE[]=__FILE__;#endif#defineBKCOLORRGB(128,128,128) //背景顏色#defineFRONTWIDTH (39+2) //前面方塊的寬度#defineFRONTHEIGHT (39+12) //前面方塊的高度#defineBKWIDTH 46 //背景方塊的寬度#defineBKHEIGHT56 //背景方塊的高度#defineROWCOUNT4 //行數(shù)#defineCOLCOUNT6 //列數(shù)#defineBLANK_STATE-1//空方塊(沒(méi)有任何動(dòng)物)///////////////////////////////////////////////////////////////////////////////CAboutDlgdialogusedforAppAboutclassCAboutDlg:publicCDialog{public: CAboutDlg();//DialogData //{{AFX_DATA(CAboutDlg) enum{IDD=IDD_ABOUTBOX}; //}}AFX_DATA //ClassWizardgeneratedvirtualfunctionoverrides //{{AFX_VIRTUAL(CAboutDlg) protected: virtualvoidDoDataExchange(CDataExchange*pDX);//DDX/DDVsupport //}}AFX_VIRTUAL//Implementationprotected: //{{AFX_MSG(CAboutDlg) //}}AFX_MSG DECLARE_MESSAGE_MAP()};CAboutDlg::CAboutDlg():CDialog(CAboutDlg::IDD){ //{{AFX_DATA_INIT(CAboutDlg) //}}AFX_DATA_INIT}voidCAboutDlg::DoDataExchange(CDataExchange*pDX){ CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CAboutDlg) //}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CAboutDlg,CDialog) //{{AFX_MSG_MAP(CAboutDlg) //Nomessagehandlers //}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CMyDlgdialogCMyDlg::CMyDlg(CWnd*pParent/*=NULL*/) :CDialog(CMyDlg::IDD,pParent){ //{{AFX_DATA_INIT(CMyDlg) //NOTE:theClassWizardwilladdmemberinitializationhere //}}AFX_DATA_INIT //NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32 //記錄方塊置為無(wú)效狀態(tài) m_nY1=BLANK_STATE; m_nX1=BLANK_STATE;//初始化行列數(shù) m_nRow=ROWCOUNT; m_nCol=COLCOUNT; //根據(jù)行列數(shù)動(dòng)態(tài)分配內(nèi)核數(shù)據(jù)數(shù)組空間 m_map=newint[m_nRow*m_nCol]; m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);}voidCMyDlg::DoDataExchange(CDataExchange*pDX){ CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CMyDlg) //NOTE:theClassWizardwilladdDDXandDDVcallshere //}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CMyDlg,CDialog) //{{AFX_MSG_MAP(CMyDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_LBUTTONDOWN() ON_COMMAND(ID_MENUITEM32773,OnMenuitem32773) ON_COMMAND(ID_MENUITEM32774,OnMenuitem32774) ON_COMMAND(ID_MENUITEM32771,OnMenuitem32771) ON_COMMAND(ID_MENUITEM32772,OnMenuitem32772) //}}AFX_MSG_MAPEND_MESSAGE_MAP()///////////////////////////////////////////////////////////////////////////////CMyDlgmessagehandlersBOOLCMyDlg::OnInitDialog(){ CDialog::OnInitDialog(); //Settheiconforthisdialog.Theframeworkdoesthisautomatically //whentheapplication'smainwindowisnotadialog SetIcon(m_hIcon,TRUE); //Setbigicon SetIcon(m_hIcon,FALSE); //Setsmallicon //獲取程序框架的設(shè)備環(huán)境 CDC*pWinDC=GetDC(); //內(nèi)存設(shè)備環(huán)境以及內(nèi)存位圖的創(chuàng)建,初始化,關(guān)聯(lián) //3D方塊邊框圖樣內(nèi)存位圖 m_mem3DBkDC.CreateCompatibleDC(pWinDC); m_mem3DBkBmp.LoadBitmap(IDB_BITMAP_3D_FRAMES); m_mem3DBkDC.SelectObject(&m_mem3DBkBmp); //動(dòng)物圖樣內(nèi)存位圖 m_memAnimalDC.CreateCompatibleDC(pWinDC); m_memAnimalBmp.LoadBitmap(IDB_BMP_ANIMAL); m_memAnimalDC.SelectObject(&m_memAnimalBmp); //整個(gè)游戲區(qū)域內(nèi)存位圖 m_MemDC.CreateCompatibleDC(pWinDC); m_memBitmap.CreateCompatibleBitmap(pWinDC, m_nCol*FRONTWIDTH+5, m_nRow*FRONTHEIGHT+5); m_MemDC.SelectObject(&m_memBitmap); //開(kāi)始一個(gè)新的游戲 StartNewGame(); //放在最桌面的前面顯示 HWNDhWnd=::AfxGetMainWnd()->m_hWnd; ::SetWindowPos(hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE|SWP_NOSIZE); returnTRUE;//returnTRUEunlessyousetthefocustoacontrol}voidCMyDlg::OnSysCommand(UINTnID,LPARAMlParam){ if((nID&0xFFF0)==IDM_ABOUTBOX) { CAboutDlgdlgAbout; dlgAbout.DoModal(); } else { CDialog::OnSysCommand(nID,lParam); }}//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,//thisisautomaticallydoneforyoubytheframework.voidCMyDlg::OnPaint(){CPaintDCdc(this);//devicecontextforpainting //先將整個(gè)游戲區(qū)域的圖像繪制到內(nèi)存位圖 GameDraw(&m_MemDC); //將內(nèi)存位圖中繪制好的圖像一次性拷貝到屏幕 dc.BitBlt(0,0,m_nCol*FRONTWIDTH,m_nCol*FRONTHEIGHT,&m_MemDC,0,0,SRCCOPY);}//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags//theminimizedwindow.HCURSORCMyDlg::OnQueryDragIcon(){ return(HCURSOR)m_hIcon;}CMyDlg::~CMyDlg(){ //釋放動(dòng)態(tài)數(shù)組空間 delete[]m_map;}voidCMyDlg::StartNewGame(){ //初始化地圖,將地圖中所有方塊區(qū)域位置置為空方塊狀態(tài) for(intiNum=0;iNum<(m_nCol*m_nRow);iNum++) { m_map[iNum]=BLANK_STATE; } //部下隨機(jī)種子 srand(time(NULL)); //生成隨機(jī)地圖 //將所有匹配成對(duì)的動(dòng)物物種放進(jìn)一個(gè)臨時(shí)的地圖中 CDWordArraytmpMap; for(inti=0;i<(m_nCol*m_nRow)/6;i++) for(intj=0;j<6;j++) tmpMap.Add(i); //每次從上面的臨時(shí)地圖中取走(獲取后并在臨時(shí)地圖刪除) //一個(gè)動(dòng)物放到地圖的空方塊上 for(i=0;i<m_nRow*m_nCol;i++) { //隨機(jī)挑選一個(gè)位置 intnIndex=(int(rand()*0.1+rand()*0.01+rand()))%tmpMap.GetSize(); //獲取該選定物件放到地圖的空方塊 m_map[i]=tmpMap.GetAt(nIndex); //在臨時(shí)地圖除去該動(dòng)物 tmpMap.RemoveAt(nIndex); } //更新顯示 Invalidate(TRUE);}BOOLCMyDlg::IsLink(intx1,inty1,intx2,inty2){//X直連方式 if(x1==x2) { if(X1_Link_X2(x1,y1,y2)) returnTRUE; } //Y直連方式 elseif(y1==y2) { if(Y1_Link_Y2(x1,x2,y1)) returnTRUE; } //一個(gè)轉(zhuǎn)彎直角的聯(lián)通方式 if(OneCornerLink(x1,y1,x2,y2)) { returnTRUE; } //兩個(gè)轉(zhuǎn)彎直角的聯(lián)通方式 elseif(TwoCornerLink(x1,y1,x2,y2)) { returnTRUE; } returnFALSE;}BOOLCMyDlg::X1_Link_X2(intx,inty1,inty2){//保證y1的值小于y2 if(y1>y2) { //數(shù)據(jù)交換 intn=y1; y1=y2; y2=n; } //直通 for(inti=y1+1;i<=y2;i++) { if(i==y2) returnTRUE; if(m_map[i*m_nCol+x]!=BLANK_STATE) break; } //左通 if(XThrough(x-1,y1,FALSE)&&XThrough(x-1,y2,FALSE)) returnTRUE; //右通 if(XThrough(x+1,y1,TRUE)&&XThrough(x+1,y2,TRUE)) returnTRUE; returnFALSE;}//Y直接連通BOOLCMyDlg::LineX(intx,inty1,inty2){if(y1>y2) { inty=y1; y1=y2; y2=y; } for(inty=y1;y<=y2;y++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(y==y2) returnTRUE; } returnFALSE;}BOOLCMyDlg::LineY(intx1,intx2,inty){if(x1>x2) { intx=x1; x1=x2; x2=x; } for(intx=x1;x<=x2;x++) { if(m_map[y*m_nCol+x]!=BLANK_STATE) returnFALSE; if(x==x2) returnTRUE; } returnFALSE;}BOOLCMyDlg::OneCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } if(y2<y1) { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2+1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1-1)) returnTRUE; returnFALSE; } else { if(LineY(x1+1,x2,y1)&&LineX(x2,y1,y2-1)) returnTRUE; if(LineY(x2-1,x1,y2)&&LineX(x1,y2,y1+1)) returnTRUE; returnFALSE; } returnFALSE;}BOOLCMyDlg::TwoCornerLink(intx1,inty1,intx2,inty2){ if(x1>x2) { intn=x1; x1=x2; x2=n; n=y1; y1=y2; y2=n; } //右通 if(XThrough(x1+1,y1,TRUE)&&XThrough(x2+1,y2,TRUE)) returnTRUE; //左通 if(XThrough(x1-1,y1,FALSE)&&XThrough(x2-1,y2,FALSE)) returnTRUE; //上通 if(YThrough(x1,y1-1,FALSE)&&YThrough(x2,y2-1,FALSE)) returnTRUE; //下通 if(YThrough(x1,y1+1,TRUE)&&YThrough(x2,y2+1,TRUE)) returnTRUE; //右 for(intx=x1+1;x<m_nCol;x++) { if(m_map[y1*m_nCol+x]>-1) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //左 for(x=x1-1;x>-1;x--) { if(m_map[y1*m_nCol+x]!=BLANK_STATE) break; if(OneCornerLink(x,y1,x2,y2)) returnTRUE; } //上 for(inty=y1-1;y>-1;y--) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } //下 for(y=y1+1;y<m_nRow;y++) { if(m_map[y*m_nCol+x1]!=BLANK_STATE) break; if(OneCornerLink(x1,y,x2,y2)) returnTRUE; } returnFALSE;}BOOLCMyDlg::XThrough(intx,inty,BOOLbAdd){if(bAdd) { for(inti=x;i<m_nCol;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=x;i++) if(m_map[y*m_nCol+i]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::YThrough(intx,inty,BOOLbAdd){if(bAdd) { for(inti=y;i<m_nRow;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } else { for(inti=0;i<=y;i++) if(m_map[i*m_nCol+x]!=BLANK_STATE) returnFALSE; } returnTRUE;}BOOLCMyDlg::IsWin(){//檢測(cè)所有是否尚有非未被消除的方塊 //(非BLANK_STATE狀態(tài)) for(inti=0;i<m_nRow*m_nCol;i++) { if(m_map[i]!=BLANK_STATE) { returnFALSE; } } returnTRUE;}voidCMyDlg::OnLButtonDown(UINTnFlags,CPointpoint){ //TODO:Addyourmessagehandlercodehereand/orcalldefault //○1.計(jì)算鼠標(biāo)點(diǎn)擊方塊的的位置 intx=point.x/FRONTWIDTH+(point.x%FRONTWIDTH?1:0)-1; inty=point.y/FRONTHEIGHT+(point.y%FRONTHEIGHT?1:0)-1; //○2.在游戲區(qū)域內(nèi)并且該區(qū)域還有該區(qū)域不是空的區(qū)域 if(x<m_nCol&&y<m_nRow&&m_map[y*m_nCol+x]!=BLANK_STATE) { //○3.假設(shè)尚未記錄第一個(gè)方塊 if(m_nX1==BLANK_STATE) { //○4記錄第一個(gè)方塊的位置 m_nX1=x; m_nY1=y; //獲取程序框架的設(shè)備環(huán)境 CDC*pWinDC=GetDC(); //臨時(shí)繪制點(diǎn)中的方塊外框 //只繪屏幕不載入內(nèi)存位圖 CPenmyPen; CPen*pOldPen; myPen.CreatePen(PS_SOLID,4,RGB(255,0,0)); pOldPen= pWinDC->SelectObject(&myPen); //方塊外框繪制,線條環(huán)繞繪制框架 pWinDC->MoveTo(x*FRONTWIDTH,y*FRONTHEIGHT); pWinDC->LineTo(x*FRONTWIDTH,(y+1)*FRONTHEIGHT); pWinDC->
溫馨提示
- 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ù)網(wǎng)僅提供信息存儲(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ì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 2023年城市馬拉松投資申請(qǐng)報(bào)告
- 年終工作總結(jié)復(fù)盤模板
- 酒店餐飲衛(wèi)生管理制度
- 《頂尖導(dǎo)購(gòu)培訓(xùn)》課件
- 食鹽物品買賣合同書(30篇)
- 2024屆高考語(yǔ)文一輪復(fù)習(xí)第1章信息類文本閱讀5第四節(jié)觀點(diǎn)評(píng)價(jià)探究題-合理評(píng)價(jià)深入探究課件
- zzjjx-kj- (新窗口) - 上海財(cái)經(jīng)大學(xué)
- 古詩(shī)詞誦讀《虞美人(春花秋月何時(shí)了)》課件 2024-2025學(xué)年統(tǒng)編版高中語(yǔ)文必修上冊(cè)-1
- 四川省廣元市高中名校2025屆高考數(shù)學(xué)三模試卷含解析
- 廣東廣州市增城區(qū)2025屆高三最后一模語(yǔ)文試題含解析
- 江西宏柏新材料股份有限公司功能性氣凝膠生產(chǎn)基地建設(shè)項(xiàng)目環(huán)評(píng)報(bào)告書
- DB33∕T 1230-2020 金屬面板保溫裝飾板外墻外保溫系統(tǒng)應(yīng)用技術(shù)規(guī)程
- 水泥物資供應(yīng)、運(yùn)輸及售后服務(wù)方案
- DB13∕T 5023-2019 有限空間作業(yè)安全規(guī)范
- 日本隧道與地下工程新技術(shù)(PPT142頁(yè))
- Tekla節(jié)點(diǎn)示例已全
- 胸膜間皮瘤的診治新進(jìn)展
- 菌群移植途徑的選擇與建立臨床應(yīng)用中國(guó)專家共識(shí)
- 可愛(ài)的嘉興三年級(jí)教材分析與教案(共23頁(yè))
- 管理學(xué)試題庫(kù)--十三套試題及答案匯總
- 小學(xué)語(yǔ)文五年級(jí)下冊(cè)期末綜合練習(xí)試題含答案(共2套)
評(píng)論
0/150
提交評(píng)論