C語言實現(xiàn)消消樂游戲的代碼分享
C和C++游戲趣味編程》一書各個章節(jié)的案例代碼,每章案例逐步利用學(xué)到的語法知識。
本章我們將編寫十字消除游戲,用戶點擊空白方塊,沿其上下左右方向?qū)ふ业谝粋€彩色方塊,如果有兩個或兩個以上顏色一致,就將其消除。在進(jìn)度條時間結(jié)束前消除足夠的方塊,可以進(jìn)入下一關(guān),效果如圖所示。
首先實現(xiàn)隨機顏色方塊的表示與繪制,鼠標(biāo)點擊與十字消除算法;然后繪制了提示框,繪制倒計時進(jìn)度條;接著進(jìn)行了得分計算、勝負(fù)判斷、多關(guān)卡功能的開發(fā);學(xué)習(xí)了地址與指針的概念,并利用地址傳遞使得程序更加模塊化;最后學(xué)習(xí)了指針和數(shù)組的知識,應(yīng)用動態(tài)數(shù)組實現(xiàn)了游戲尺寸的動態(tài)大小調(diào)整。
源碼
#include <graphics.h> #include <conio.h> #include <stdio.h> #include <time.h> #include <stdlib.h> # define BlockSize 40 // 小方塊的長寬大小 # define ColorTypeNum 9 // 除了空白方塊外,其他方塊的顏色的個數(shù) struct Block // 小方塊結(jié)構(gòu)體 { int x,y; // x y坐標(biāo) int colorId; // 對應(yīng)顏色的下標(biāo) int i,j; // 小方塊在二維數(shù)組中的i j下標(biāo) }; // 全局變量 int RowNum; // 游戲畫面一共RowNum行小方塊 int ColNum; // 游戲畫面一共ColNum列小方塊 Block **blocks = NULL; // 動態(tài)二維數(shù)組指針,存儲所有方塊數(shù)據(jù) COLORREF colors[ColorTypeNum+1]; // 顏色數(shù)組,小方塊可能的幾種顏色 int score; // 得分?jǐn)?shù),也就是消去的方塊的個數(shù) float maxTime; // 這一關(guān)游戲的總時長 float totalTime; // 減去扣分項后的游戲總時長 float remainTime; // 剩余時間 clock_t start, finish; // 用于計時的變量 int level = 1; // 當(dāng)前關(guān)卡序號 int noZeroBlockNum; // 非空白區(qū)域的磚塊的個數(shù) void drawBlockHint(int i,int j,COLORREF color,int isfill) // 繪制出一個提示線框出來 { setlinecolor(color); setfillcolor(color); if (isfill==1) // 鼠標(biāo)點擊中的方塊,畫填充方塊提示 fillrectangle(blocks[i][j].x,blocks[i][j].y,blocks[i][j].x+BlockSize,blocks[i][j].y+BlockSize); if (isfill==0) // 上下左右四個方向找到的4個方塊,畫線框提示 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"); // 如果打不開的話,就新建一個文件,其得分記錄為0分 if (fp==NULL) { writeRecordFile(0); return 0; } else // 能打開這個文件,就讀取下最高分記錄 { fscanf(fp,"%d",&recordScore); fclose(fp); return recordScore; } } void startup() // 初始化函數(shù) { int i,j; start = clock(); // 記錄當(dāng)前運行時刻 if (level>1) // 如果不是第1關(guān),則先清除二維數(shù)組內(nèi)存,再重新開辟內(nèi)存空間 { for (i=0;i<RowNum;i++) free(blocks[i]); free(blocks); } // 根據(jù)是第幾關(guān),調(diào)整這一關(guān)對應(yīng)的游戲畫面的大小 RowNum = 12 + level/2; // 行數(shù)添加的慢一些,是一個長方形的形狀 ColNum = 20 + level; // 開辟動態(tài)二維數(shù)組 blocks = (Block **) malloc(RowNum*sizeof(Block *)); for (i=0;i<RowNum;i++) blocks[i] = (Block *) malloc(ColNum*sizeof(Block)); maxTime = 200 + level*10; // 這一關(guān)游戲設(shè)定的總時長,每關(guān)時長+10秒 totalTime = maxTime; // 游戲總時長,每次出錯,會扣10秒鐘 int width = BlockSize*ColNum; // 設(shè)定游戲畫面的大小 int height = BlockSize*(RowNum+3); // 最下面用來顯示一些提示信息 initgraph(width,height); setbkcolor(RGB(220,220,220)); setlinestyle(PS_SOLID,2); cleardevice(); srand(time(0)); BeginBatchDraw(); // 開始批量繪制 score = 0; // 得分?jǐn)?shù),也就是消去的方塊的個數(shù) noZeroBlockNum = 0; // 非空白區(qū)域的磚塊的個數(shù) colors[0] = RGB(220,220,220); // 顏色數(shù)組第一種顏色為灰白色,表示空白小方塊 for (i=1;i<ColorTypeNum+1;i++) // 其他幾種顏色為彩色 colors[i] = HSVtoRGB((i-1)*40,0.6,0.8); // 對blocks二維數(shù)組進(jìn)行初始化 for (i=0;i<RowNum;i++) { for (j=0;j<ColNum;j++) { // 取隨機數(shù),1-6設(shè)為彩色色塊,其他為空白色塊,這樣為空白色塊的幾率高一些 // 初始化時,空白色塊多一些,符合游戲的設(shè)定 int t = rand()%(int(ColorTypeNum*1.5)); // 取隨機數(shù) if (t<ColorTypeNum+1) blocks[i][j].colorId = t; // 小方塊的顏色序號 else // 其他情況,都為空白顏色方塊 blocks[i][j].colorId = 0; // 小方塊的顏色序號 blocks[i][j].x = j*BlockSize; // 小方塊左上角坐標(biāo) blocks[i][j].y = i*BlockSize; // blocks[i][j].i = i; // 存儲當(dāng)前小方塊在二維數(shù)組中的下標(biāo) blocks[i][j].j = j; if (blocks[i][j].colorId != 0) noZeroBlockNum++; // 統(tǒng)計隨機產(chǎn)生的方塊中,非零方塊的個數(shù) } } } void show() // 繪制函數(shù) { cleardevice(); // 清屏 setlinecolor(RGB(255,255,255)); // 白色線條 int i,j; for (i=0;i<RowNum;i++) { for (j=0;j<ColNum;j++) { // 以對應(yīng)的顏色、坐標(biāo)畫出所有的小方塊 setfillcolor(colors[blocks[i][j].colorId]); fillrectangle(blocks[i][j].x,blocks[i][j].y,blocks[i][j].x+BlockSize,blocks[i][j].y+BlockSize); } } // 根據(jù)剩余時間,繪制一個倒計時進(jìn)度條,進(jìn)度條按最大時間maxTime秒繪制 setlinecolor(RGB(255,0,0)); setfillcolor(RGB(255,0,0)); fillrectangle(0,BlockSize*(RowNum+0.2),remainTime*BlockSize*ColNum/maxTime,BlockSize*(RowNum+0.8)); // 輸出得分文字 TCHAR s[80]; setbkmode(TRANSPARENT); _stprintf(s, _T("%d"), score); settextcolor(RGB(0,0,0)); settextstyle(22, 0, _T("宋體")); outtextxy(BlockSize*(ColNum/2-0.1), BlockSize*(RowNum+0.2), s); // 輸出一些游戲提示信息 _stprintf(s, _T("點擊空白方塊,其十字區(qū)域有兩個或以上相同顏色方塊則消除;不能消除扣時間")); outtextxy(BlockSize*(ColNum/15.0), BlockSize*(RowNum+1.2), s); _stprintf(s, _T("目前第 %d 關(guān),時間結(jié)束前得分達(dá)到 %d 可進(jìn)入下一關(guān)"),level,int(noZeroBlockNum*0.9)); outtextxy(BlockSize*(ColNum/5.0), BlockSize*(RowNum+2.2), s); FlushBatchDraw(); // 批量繪制 } void updateWithoutInput() // 和輸入無關(guān)的更新 { // 倒計時減少 finish = clock(); // 當(dāng)前時刻 // 從startup運行后,這一關(guān)游戲運行了多少秒 double duration = (double)(finish - start) / CLOCKS_PER_SEC; remainTime = totalTime-duration; // 游戲剩余的時間 // 如果時間到了 if (remainTime<=0) { // 讀一下文件記錄,如果當(dāng)前得分超過記錄 if (score > readRecordFile()) { // 更新下得分記錄 writeRecordFile(score); // 顯示恭喜超過記錄 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ù),重新開始游戲 return; } } void updateWithInput() // 和輸入有關(guān)的更新 { if (remainTime<=0) // 時間到了,不要操作 return; int i,j; MOUSEMSG m; if (MouseHit()) { m = GetMouseMsg(); if(m.uMsg == WM_LBUTTONDOWN) // 當(dāng)按下鼠標(biāo)左鍵時 { // 獲得點擊的小方塊的下標(biāo) int clicked_i = int(m.y)/BlockSize; int clicked_j = int(m.x)/BlockSize; // 點擊到下面提示部分了,不用處理,函數(shù)返回 if (clicked_i>=RowNum) return; // 如果當(dāng)前點擊的不是空白方塊,不需要處理,返回 if (blocks[clicked_i][clicked_j].colorId!=0) return; show(); // 先顯示其他方塊,再繪制提示框,后繪制的在最前面 // 被點擊到的空白方塊,繪制下填充灰色方塊提示框 drawBlockHint(clicked_i,clicked_j,RGB(100,100,100),1); // 定義數(shù)組,存儲上、下、左、右四個方向找到第一個不是空白的方塊 Block fourBlocks[4] = {blocks[clicked_i][clicked_j]}; // 初始化為這個空白的點擊的方塊 int search; // 尋找下標(biāo) // 向上找 for (search=0;clicked_i-search>=0;search++) { if (blocks[clicked_i-search][clicked_j].colorId!=0) // 找到第一個顏色不是空白的方塊 { fourBlocks[0] = blocks[clicked_i-search][clicked_j]; // 賦給這個存儲的數(shù)組 break; } } // 向下找 for (search=0;clicked_i+search<RowNum;search++) { if (blocks[clicked_i+search][clicked_j].colorId!=0) // 找到第一個顏色不是空白的方塊 { fourBlocks[1] = blocks[clicked_i+search][clicked_j]; // 賦給這個存儲的數(shù)組 break; } } // 向左找 for (search=0;clicked_j-search>=0;search++) { if (blocks[clicked_i][clicked_j-search].colorId!=0) // 找到第一個顏色不是空白的方塊 { fourBlocks[2] = blocks[clicked_i][clicked_j-search]; // 賦給這個存儲的數(shù)組 break; } } // 向右找 for (search=0;clicked_j+search<ColNum;search++) { if (blocks[clicked_i][clicked_j+search].colorId!=0) // 找到第一個顏色不是空白的方塊 { fourBlocks[3] = blocks[clicked_i][clicked_j+search]; // 賦給這個存儲的數(shù)組 break; } } // 統(tǒng)計fourBlocks的四個小方塊,有沒有同樣顏色數(shù)目大于等于2的 int colorStatistics[ColorTypeNum+1] = {0}; // 初始化個數(shù)為0 int isBadClick = 1; // 假設(shè)點擊的方塊不合適,十字區(qū)域沒有有效消除的方塊 for (i=1;i<ColorTypeNum+1;i++) // i=0是空白顏色,不要統(tǒng)計 { for (j=0;j<4;j++) // 遍歷fourBlocks { if (fourBlocks[j].colorId==i) colorStatistics[i]++; // 方塊顏色為非零的i的話,把對應(yīng)的統(tǒng)計個數(shù)+1 } if (colorStatistics[i]>=2) // 如果這種顏色方塊個數(shù)大于等于2 { isBadClick = 0; // 能消除了,這次點擊是好的操作 // 把對應(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); // 顏色序號設(shè)為0,也就是空白的灰白色 blocks[fourBlocks[j].i][fourBlocks[j].j].colorId = 0; } } score += colorStatistics[i]; // 得分加上消除的方塊數(shù) } } // 點擊的方塊,十字區(qū)域沒有能消除的方塊,為錯誤點擊,減去10秒鐘時間 if (isBadClick==1) totalTime -= 10; FlushBatchDraw(); // 批量繪制 Sleep(300); // 繪制好提示框后暫停300毫秒 } // while 當(dāng)按下鼠標(biāo)左鍵時 } } int main() // 主函數(shù)運行 { startup(); while (1) { show(); updateWithoutInput(); updateWithInput(); } closegraph(); return 0; }
這一章主要講解了指針的相關(guān)語法知識,學(xué)習(xí)了倒計時的方法,實現(xiàn)了十字消除游戲。讀者可以嘗試在本章代碼基礎(chǔ)上繼續(xù)改進(jìn):
1、實現(xiàn)隨著游戲的進(jìn)行,通過關(guān)卡要求消除方塊的比例越來越高;
2、利用文件讀寫,實現(xiàn)關(guān)卡數(shù)據(jù)與最高分的記錄與讀取。
到此這篇關(guān)于C語言實現(xiàn)消消樂游戲的代碼分享的文章就介紹到這了,更多相關(guān)C語言消消樂游戲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C++實現(xiàn)LeetCode(647.回文子字符串)
這篇文章主要介紹了C++實現(xiàn)LeetCode(647.回文子字符串),本篇文章通過簡要的案例,講解了該項技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07