?
十字消除,休閑小游戲,在規(guī)定時(shí)間內(nèi),只要是十字線(xiàn)能連接到的相同顏色的方塊,就能獲得相應(yīng)的得分,如果點(diǎn)擊后沒(méi)有能夠消除的方塊會(huì)扣除時(shí)間,是一款益智小游戲。
我們將編寫(xiě)十字消除游戲,用戶(hù)點(diǎn)擊空白方塊,沿其上下左右方向?qū)ふ业谝粋€(gè)彩色方塊,如果有兩個(gè)或兩個(gè)以上顏色一致,就將其消除。在進(jìn)度條時(shí)間結(jié)束前消除足夠的方塊,可以進(jìn)入下一關(guān)。
?
繪制過(guò)程
首先實(shí)現(xiàn)隨機(jī)顏色方塊的表示與繪制,鼠標(biāo)點(diǎn)擊與十字消除算法;然后繪制了提示框,繪制倒計(jì)時(shí)進(jìn)度條;接著進(jìn)行了得分計(jì)算、勝負(fù)判斷、多關(guān)卡功能的開(kāi)發(fā);學(xué)習(xí)了地址與指針的概念,并利用地址傳遞使得程序更加模塊化;最后學(xué)習(xí)了指針和數(shù)組的知識(shí),應(yīng)用動(dòng)態(tài)數(shù)組實(shí)現(xiàn)了游戲尺寸的動(dòng)態(tài)大小調(diào)整
在規(guī)定時(shí)間內(nèi),只要是十字線(xiàn)能連接到的相同顏色的方塊,就能獲得相應(yīng)的得分,如果點(diǎn)擊后沒(méi)有能夠消除的方塊會(huì)扣除時(shí)間。
操作方法
鼠標(biāo)點(diǎn)擊兩個(gè)或多個(gè)顏色相同方塊的十字線(xiàn)的中心,便能成功消除方塊。
注意是點(diǎn)擊空白格子而不是彩色方塊哦,點(diǎn)錯(cuò)會(huì)扣時(shí)間,點(diǎn)左下角的[顯示圖標(biāo)提示]可切換到圖標(biāo)模式
?
代碼示例:
?
#include#include #include #include #include # define BlockSize 40 // 小方塊的長(zhǎng)寬大小 # define ColorTypeNum 9 // 除了空白方塊外,其他方塊的顏色的個(gè)數(shù) struct Block // 小方塊結(jié)構(gòu)體 { int x,y; // x y坐標(biāo) int colorId; // 對(duì)應(yīng)顏色的下標(biāo) int i,j; // 小方塊在二維數(shù)組中的i j下標(biāo) }; // 全局變量 int RowNum; // 游戲畫(huà)面一共RowNum行小方塊 int ColNum; // 游戲畫(huà)面一共ColNum列小方塊 Block **blocks = NULL; // 動(dòng)態(tài)二維數(shù)組指針,存儲(chǔ)所有方塊數(shù)據(jù) COLORREF colors[ColorTypeNum+1]; // 顏色數(shù)組,小方塊可能的幾種顏色 int score; // 得分?jǐn)?shù),也就是消去的方塊的個(gè)數(shù) float maxTime; // 這一關(guān)游戲的總時(shí)長(zhǎng) float totalTime; // 減去扣分項(xiàng)后的游戲總時(shí)長(zhǎng) float remainTime; // 剩余時(shí)間 clock_t start, finish; // 用于計(jì)時(shí)的變量 int level = 1; // 當(dāng)前關(guān)卡序號(hào) int noZeroBlockNum; // 非空白區(qū)域的磚塊的個(gè)數(shù) void drawBlockHint(int i,int j,COLORREF color,int isfill) // 繪制出一個(gè)提示線(xiàn)框出來(lái) { setlinecolor(color); setfillcolor(color); if (isfill==1) // 鼠標(biāo)點(diǎn)擊中的方塊,畫(huà)填充方塊提示 fillrectangle(blocks[i][j].x,blocks[i][j].y,blocks[i][j].x+BlockSize,blocks[i][j].y+BlockSize); if (isfill==0) // 上下左右四個(gè)方向找到的4個(gè)方塊,畫(huà)線(xiàn)框提示 rectangle(blocks[i][j].x,blocks[i][j].y,blocks[i][j].x+BlockSize,blocks[i][j].y+BlockSize); } void writeRecordFile(int recordScore) //保存最高分?jǐn)?shù)據(jù)文件 { FILE *fp; fp = fopen(".\gameRecord.dat","w"); fprintf(fp,"%d",recordScore); fclose(fp); } int readRecordFile() //讀取最高分?jǐn)?shù)據(jù)文件 { int recordScore; FILE *fp; fp = fopen(".\gameRecord.dat","r"); // 如果打不開(kāi)的話(huà),就新建一個(gè)文件,其得分記錄為0分 if (fp==NULL) { writeRecordFile(0); return 0; } else // 能打開(kāi)這個(gè)文件,就讀取下最高分記錄 { fscanf(fp,"%d",&recordScore); fclose(fp); return recordScore; } } void startup() // 初始化函數(shù) { int i,j; start = clock(); // 記錄當(dāng)前運(yùn)行時(shí)刻 if (level>1) // 如果不是第1關(guān),則先清除二維數(shù)組內(nèi)存,再重新開(kāi)辟內(nèi)存空間 { for (i=0;i readRecordFile()) { // 更新下得分記錄 writeRecordFile(score); // 顯示恭喜超過(guò)記錄 show(); settextcolor(RGB(255,0,0)); settextstyle(100, 0, _T("黑體")); outtextxy(BlockSize*(ColNum/30.0), BlockSize*(RowNum/3.0), _T("恭喜打破得分記錄")); FlushBatchDraw(); // 批量繪制 Sleep(2000); } if (score>=int(noZeroBlockNum*0.9)) { level ++; // 如果得分達(dá)到要求,消除掉非空白方塊數(shù)目的90%,關(guān)卡加1 } startup(); // 調(diào)用初始化函數(shù),重新開(kāi)始游戲 return; } } void updateWithInput() // 和輸入有關(guān)的更新 { if (remainTime<=0) // 時(shí)間到了,不要操作 return; int i,j; MOUSEMSG m; if (MouseHit()) { m = GetMouseMsg(); if(m.uMsg == WM_LBUTTONDOWN) // 當(dāng)按下鼠標(biāo)左鍵時(shí) { // 獲得點(diǎn)擊的小方塊的下標(biāo) int clicked_i = int(m.y)/BlockSize; int clicked_j = int(m.x)/BlockSize; // 點(diǎn)擊到下面提示部分了,不用處理,函數(shù)返回 if (clicked_i>=RowNum) return; // 如果當(dāng)前點(diǎn)擊的不是空白方塊,不需要處理,返回 if (blocks[clicked_i][clicked_j].colorId!=0) return; show(); // 先顯示其他方塊,再繪制提示框,后繪制的在最前面 // 被點(diǎn)擊到的空白方塊,繪制下填充灰色方塊提示框 drawBlockHint(clicked_i,clicked_j,RGB(100,100,100),1); // 定義數(shù)組,存儲(chǔ)上、下、左、右四個(gè)方向找到第一個(gè)不是空白的方塊 Block fourBlocks[4] = {blocks[clicked_i][clicked_j]}; // 初始化為這個(gè)空白的點(diǎn)擊的方塊 int search; // 尋找下標(biāo) // 向上找 for (search=0;clicked_i-search>=0;search++) { if (blocks[clicked_i-search][clicked_j].colorId!=0) // 找到第一個(gè)顏色不是空白的方塊 { fourBlocks[0] = blocks[clicked_i-search][clicked_j]; // 賦給這個(gè)存儲(chǔ)的數(shù)組 break; } } // 向下找 for (search=0;clicked_i+search =0;search++) { if (blocks[clicked_i][clicked_j-search].colorId!=0) // 找到第一個(gè)顏色不是空白的方塊 { fourBlocks[2] = blocks[clicked_i][clicked_j-search]; // 賦給這個(gè)存儲(chǔ)的數(shù)組 break; } } // 向右找 for (search=0;clicked_j+search =2) // 如果這種顏色方塊個(gè)數(shù)大于等于2 { isBadClick = 0; // 能消除了,這次點(diǎn)擊是好的操作 // 把對(duì)應(yīng)十字區(qū)域要消除的方塊顏色改成空白顏色 for (j=0;j<4;j++) // 遍歷fourBlocks { if (fourBlocks[j].colorId==i) { // 要消除的方塊區(qū)域繪制提示框 drawBlockHint(fourBlocks[j].i,fourBlocks[j].j,RGB(0,0,0),0); // 顏色序號(hào)設(shè)為0,也就是空白的灰白色 blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0; } } score += colorStatistics[i]; // 得分加上消除的方塊數(shù) } } // 點(diǎn)擊的方塊,十字區(qū)域沒(méi)有能消除的方塊,為錯(cuò)誤點(diǎn)擊,減去10秒鐘時(shí)間 if (isBadClick==1) totalTime -= 10; FlushBatchDraw(); // 批量繪制 Sleep(300); // 繪制好提示框后暫停300毫秒 } // while 當(dāng)按下鼠標(biāo)左鍵時(shí) } } int main() // 主函數(shù)運(yùn)行 { startup(); while (1) { show(); updateWithoutInput(); updateWithInput(); } closegraph(); return 0; }
?
這一節(jié)主要講解了指針的相關(guān)語(yǔ)法知識(shí),學(xué)習(xí)了倒計(jì)時(shí)的方法,實(shí)現(xiàn)了十字消除游戲。讀者可以嘗試在本章代碼基礎(chǔ)上繼續(xù)改進(jìn):
1、實(shí)現(xiàn)隨著游戲的進(jìn)行,通過(guò)關(guān)卡要求消除方塊的比例越來(lái)越高;
2、利用文件讀寫(xiě),實(shí)現(xiàn)關(guān)卡數(shù)據(jù)與最高分的記錄與讀取。
讀者也可以參考本章的開(kāi)發(fā)思路,嘗試設(shè)計(jì)并分步驟實(shí)現(xiàn)消消樂(lè)、消滅星星、寶石迷陣等各種消除類(lèi)游戲。
審核編輯:湯梓紅
評(píng)論
查看更多