本文實(shí)例為大家分享了C語言實(shí)現(xiàn)俄羅斯方塊的具體代碼,供大家參考,具體內(nèi)容如下
GitHub:【C語言】實(shí)現(xiàn)俄羅斯方塊源代碼
Head.h
#ifndef _HEAD_H_#define _HEAD_H_#include<graphics.h>#include<stdio.h>#include<conio.h>#include<stdlib.h>#include<time.h>#include<string.h>#define _CRT_SECURE_NO_WARNINGS 1//界面的相關(guān)的參數(shù)#define WALL_SQUARE_WIDTH 10 //圍墻方塊的寬度#define xWALL_SQUARE_NUM 30 //x軸方向的方塊的數(shù)目#define yWALL_SQUARE_WIDTH 46 //y軸方向的方塊的數(shù)目#define GAME_WALL_WIDTH (WALL_SQUARE_WIDTH*xWALL_SQUARE_NUM) //游戲區(qū)域的寬度 300 #define GAME_WALL_HTGH (WALL_SQUARE_WIDTH*yWALL_SQUARE_WIDTH) //游戲區(qū)域的高度 460#define WINDOW_WIDTH 480 // 游戲總窗口寬度 480 #define WINDOW_HIGH 460 // 游戲總窗口高度 460//定義俄羅斯方塊的相關(guān)參數(shù)#define ROCK_SQUARE_WIDTH (2*WALL_SQUARE_WIDTH) //俄羅斯方塊的大小是圍墻的兩倍 20#define xROCK_SQUARE_NUM ((GAME_WALL_WIDTH -20)/ROCK_SQUARE_WIDTH) // 游戲區(qū)x軸放的方塊數(shù)目:14 #define yROCK_SQUARE_NUM ((GAME_WALL_HTGH -20)/ROCK_SQUARE_WIDTH) // 游戲區(qū)y軸放的方塊數(shù)目:22//定義移動(dòng)方塊的相關(guān)操作#define DIRECT_UP 3 #define DIRECT_DOWN 2 #define DIRECT_LEFT -1 #define DIRECT_RIGHT 1 /*數(shù)據(jù)結(jié)構(gòu)-線性表(結(jié)構(gòu)體數(shù)組)*/typedef struct ROCK{ //用來表示方塊的形狀(每一個(gè)字節(jié)是8位,用每4位表示方塊中的一行) unsigned short rockShapeBits; int nextRockIndex; //下一個(gè)方塊,在數(shù)組中的下標(biāo) } RockType;//方塊在圖形窗口中的位置(即定位4*4大塊的左上角坐標(biāo)) typedef struct LOCATE{ int left; int top;} RockLocation_t;//全局變量-游戲板的狀態(tài)描述(即表示當(dāng)前界面哪些位置有方塊) //0表示沒有,1表示有(多加了兩行和兩列,形成一個(gè)圍墻,便于判斷方塊是否能夠移動(dòng)) int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };int game_socres = 0; //全局分?jǐn)?shù)// 把俄羅斯方塊的19種類放到數(shù)組中int rockTypeNum = 19;RockType RockArray[19] = { (0, 0) };//預(yù)覽區(qū)的方塊的位置RockLocation_t preRockLocation = {GAME_WALL_WIDTH+70,70};//每次生成初始化方塊的位置RockLocation_t initRockLocation = { (WALL_SQUARE_WIDTH + 100), WALL_SQUARE_WIDTH };//分?jǐn)?shù)顯示的位置//各個(gè)文件中的函數(shù)// 畫出界面以及畫出方塊Draw.h中void DrawGameWindow();void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed);//初始化Init源文件void InitGame();//game.hvoid PlayGame();bool IsGameOver();#endifDraw.h
#include"Head.h"http://畫出游戲界面void DrawGameWindow(){ //先畫出圍墻 setcolor(BLUE); setlinestyle(PS_SOLID,NULL,0); setfillcolor(BLUE); //畫出上下圍墻 for (int x = WALL_SQUARE_WIDTH; x <= GAME_WALL_WIDTH; x += WALL_SQUARE_WIDTH) { fillrectangle(x - WALL_SQUARE_WIDTH, 0, x, WALL_SQUARE_WIDTH); //上 fillrectangle(x - WALL_SQUARE_WIDTH, GAME_WALL_HTGH - WALL_SQUARE_WIDTH, x, GAME_WALL_HTGH);//下 } //畫出左右圍墻 for (int y = WALL_SQUARE_WIDTH; y <= GAME_WALL_HTGH; y += WALL_SQUARE_WIDTH) { fillrectangle(0, y, WALL_SQUARE_WIDTH, y + WALL_SQUARE_WIDTH);//左 fillrectangle(GAME_WALL_WIDTH - WALL_SQUARE_WIDTH, y, GAME_WALL_WIDTH, y + WALL_SQUARE_WIDTH);//右 } //畫出右邊統(tǒng)計(jì)分?jǐn)?shù)及相關(guān)東西 //畫出分割線 setcolor(WHITE); setlinestyle(PS_DASH,2); line(GAME_WALL_WIDTH + 20, 0, GAME_WALL_WIDTH + 20, GAME_WALL_HTGH); //設(shè)置字體 LOGFONT font; gettextstyle(&font); settextstyle(18, 0, _T("宋體")); font.lfQuality = ANTIALIASED_QUALITY;//設(shè)置輸出效果為抗鋸齒 //1顯示預(yù)覽形狀 outtextxy(GAME_WALL_WIDTH + 80, 30, _T("預(yù)覽")); outtextxy(GAME_WALL_WIDTH + 80, 170, _T("分?jǐn)?shù)")); outtextxy(GAME_WALL_WIDTH + 65, 250, _T("操作說明")); outtextxy(GAME_WALL_WIDTH + 40, 290, _T("w a s d控制方向")); outtextxy(GAME_WALL_WIDTH + 40, 335, _T("空格 暫停")); //顯示分?jǐn)?shù) setcolor(RED); outtextxy(GAME_WALL_WIDTH + 90, 200, '0');}//在游戲區(qū)顯示編號(hào)為rockIdx的方塊void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed){ int color;//方塊的填充顏色 int lineColor = WHITE;//線的顏色 int boardFalg = 0; int xRock = 0; int yRock = 0; unsigned short rockCode = RockArray[rockIdx].rockShapeBits; //如果displayed為true的話,將方塊塊顏色設(shè)置為white,game_board對(duì)應(yīng)的位置設(shè)置為1; //如果displayed為false的話,將方塊塊顏色設(shè)置為black,game_board對(duì)應(yīng)的位置設(shè)置為0; displayed ? (color = RED, boardFalg = 1) : (color = BLACK,lineColor = BLACK, boardFalg = 0); setcolor(lineColor); setfillcolor(color); setlinestyle(PS_SOLID);//設(shè)置為實(shí)線, xRock = LocatePtr->left; yRock = LocatePtr->top; int count = 0;//每4個(gè)換行,記錄坐標(biāo)偏移量 unsigned short mask = 1; for (int i = 1; i <= 16; ++i) { mask = 1 << (16 - i); if ((rockCode & mask) != 0) //如果不為0的話,就畫出小方塊 { fillrectangle(xRock , yRock, xRock + ROCK_SQUARE_WIDTH, yRock + ROCK_SQUARE_WIDTH); } if (i % 4 == 0) //換行 { yRock = yRock + ROCK_SQUARE_WIDTH; xRock = xRock = LocatePtr->left; } else { xRock += ROCK_SQUARE_WIDTH; } }}Init.h
#include"Head.h"static void ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit);static void ReadRcok();void InitGame(){ //把全局游戲游戲版初始化,邊界初始化為1 for (int i = 0; i < xROCK_SQUARE_NUM + 2; i++) { game_board[0][i] = 1; //上邊界 game_board[yROCK_SQUARE_NUM + 1][i] = 1; //下邊界 } for (int i = 0; i < yROCK_SQUARE_NUM + 2; i++) { game_board[i][0] = 1 ; //左邊界 game_board[i][xROCK_SQUARE_NUM + 1] = 1; //右邊界 } //讀取俄羅斯方塊 ReadRcok();}//從文件中讀取方塊的形狀存儲(chǔ)到rockArray中void ReadRcok(){ FILE* fp = fopen("RockShape.ini","r"); if (NULL == fp) { printf("打開文件失敗/n"); return; } unsigned char readBuf[1024]; //fp讀取到字符串readbuf中 unsigned short rockShapeBit = 0;//存放方塊形狀,占16比特位 unsigned char rockShapeStr[16];//存放方塊字符串 int ShapeStrIdx = 0; int rockNum = 0;//統(tǒng)計(jì)方塊的個(gè)數(shù)以及存放方塊數(shù)組RockArray的下標(biāo) int rocknext = 0;//方塊數(shù)組中下一個(gè)形狀 int rockShapeStart = 0;//同一類型的形狀 while (true) { size_t readSize = fread(readBuf, 1, 1024, fp); if (readSize == 0) break; //處理readbuf for (size_t idx = 0; idx < readSize; ++idx) { //將字符存放到rockShapeStr中 while (ShapeStrIdx < 16 && idx < readSize) { if (readBuf[idx] == '@' || readBuf[idx] == '#') { rockShapeStr[ShapeStrIdx] = (unsigned char)readBuf[idx]; ++ShapeStrIdx; } ++idx; //可能idx == readSize了 if (readBuf[idx] == '*')//修改上一次方塊的next值 { idx += 5; RockArray[--rockNum].nextRockIndex = rockShapeStart; rockNum++; rockShapeStart = rockNum; rocknext = rockShapeStart ; } } //可能沒有填滿 if (ShapeStrIdx < 16) { break; } else //填滿shapestr { ShapeStrIdx = 0;//置0 //將rockShapeStr 轉(zhuǎn)為rockShapeBit ShapeStrToBit(rockShapeStr, rockShapeBit); rocknext++; RockArray[rockNum].rockShapeBits = rockShapeBit; RockArray[rockNum].nextRockIndex = rocknext; rockNum++; } } } fclose(fp);}//將從文件中讀取的字符串(長度默認(rèn)為16)轉(zhuǎn)換成 unsigned shortvoid ShapeStrToBit(unsigned char *rockShapeStr, unsigned short& rockShapeBit){ rockShapeBit = 0; for (size_t idx = 0; idx < 16; ++idx) { if (rockShapeStr[idx] == '@') //1 { rockShapeBit |= (1 << (16 - idx - 1)); } // #為0 不需要處理 }}game.h
#include"Head.h"#define _CRT_SECURE_NO_WARNINGS 1bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction);void SetGameBoardFlag(int rockIdx, RockLocation_t* curRockLocation);void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation);void FullLine();void UpdateSocres(int scores);void DelCurLine(int rowIdx);bool IsGameOver();void PlayGame(){ char userHit = 0;//用戶敲擊鍵盤 int curRockIndex = 0;//當(dāng)前方塊的rockArray下標(biāo) int nextRockIndex = 0;//下次 RockLocation_t curRockLocation; curRockLocation.left = initRockLocation.left; curRockLocation.top = initRockLocation.top; DWORD oldtime = 0; srand((unsigned int)time(NULL)); curRockIndex = rand() % rockTypeNum; nextRockIndex = rand() % rockTypeNum; //畫出預(yù)覽區(qū)初始化方塊 //在初始位置和預(yù)覽區(qū)顯示方塊形狀 DisplayRock(curRockIndex, &initRockLocation, 1); DisplayRock(nextRockIndex, &preRockLocation, 1); bool moveAbled = false; while (true) { //判斷當(dāng)前方塊是否落地(判斷能否再下移):如果落地,判斷是否滿行,再判斷是否結(jié)束游戲, 改變game_board ,畫出下次初始化的方塊,以及生成新的預(yù)覽方塊 // moveAbled = MoveAble(curRockIndex, &curRockLocation, DIRECT_DOWN); if (!moveAbled) //判斷是否落地,不能下移表示落地 { //修改game_board的值 SetGameBoardFlag(curRockIndex, &curRockLocation); FullLine(); if (IsGameOver()) { MessageBox(NULL, _T("游戲結(jié)束"), _T("GAME OVER"), MB_OK); exit(0); } //為下次生成模塊開始準(zhǔn)備 DisplayRock(nextRockIndex, &preRockLocation, false);//擦除舊的方塊 curRockIndex = nextRockIndex; nextRockIndex = rand() % rockTypeNum; //生成新的預(yù)覽方塊 DisplayRock(curRockIndex, &initRockLocation, 1); DisplayRock(nextRockIndex, &preRockLocation, 1); FlushBatchDraw(); //修改curRockLocation的值 curRockLocation.left = initRockLocation.left; curRockLocation.top = initRockLocation.top; } if (kbhit()) //如果敲擊鍵盤了 就處理按鍵 { userHit = getch(); UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation); } //沒有 就自動(dòng)下移一個(gè)單位 :不能用else,因?yàn)榭赡馨存I不是上下左右 DWORD newtime = GetTickCount(); if (newtime - oldtime >= (unsigned int)(300) && moveAbled == TRUE) { oldtime = newtime; DisplayRock(curRockIndex, &curRockLocation, false); curRockLocation.top += ROCK_SQUARE_WIDTH; //下落一格 } //AutomaticDownMove(curRockIndex, &curRockLocation); //畫出新方塊 DisplayRock(curRockIndex, &curRockLocation, 1); FlushBatchDraw(); Sleep(20); }}//響應(yīng)鍵盤命令時(shí)間void UserHitKeyBoard(char userHit, int* RockIndex, RockLocation_t* curRockLocation){ switch (userHit) { case 'W': case 'w'://↑ if (MoveAble(RockArray[*RockIndex].nextRockIndex, curRockLocation, DIRECT_UP)) { DisplayRock(*RockIndex, curRockLocation, false); *RockIndex = RockArray[*RockIndex].nextRockIndex; } break; case 'S': case 's'://↓ if (MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN)) { DisplayRock(*RockIndex, curRockLocation, false); curRockLocation->top += 2 * (ROCK_SQUARE_WIDTH); if (!MoveAble(*RockIndex, curRockLocation, DIRECT_DOWN)) { curRockLocation->top -= ROCK_SQUARE_WIDTH; } } break; case 'A': case 'a': //← if (MoveAble(*RockIndex, curRockLocation, DIRECT_LEFT)) { DisplayRock(*RockIndex, curRockLocation, false); curRockLocation->left -= ROCK_SQUARE_WIDTH; } break; case 'D': case 'd': //→ if (MoveAble(*RockIndex, curRockLocation, DIRECT_RIGHT)) { DisplayRock(*RockIndex, curRockLocation, FALSE); curRockLocation->left += ROCK_SQUARE_WIDTH; } break; case ' ': //暫停 while (1) { userHit = getch(); if (userHit == ' ') break; } break; default: break; }}//判斷是否滿行,滿行消除,然后計(jì)算得分void FullLine(){ bool linefull = true; int idx = yROCK_SQUARE_NUM;//從最后一行往上查找 22 int count = 0; while (count != xROCK_SQUARE_NUM ) //遇到空行 14 { linefull = true; count = 0; for (int i = 1; i <= xROCK_SQUARE_NUM; ++i) { if (game_board[idx][i] == 0) { linefull = false; count++; } } if (linefull) //滿行,消除當(dāng)前行,更新分?jǐn)?shù) { DelCurLine(idx); game_socres += 3; UpdateSocres(game_socres); idx++;//因?yàn)橄旅嬉獪p1 } idx--; }}void UpdateSocres(int scores){ setcolor(RED); TCHAR s[10]; _stprintf(s, _T("%d"), scores); outtextxy(GAME_WALL_WIDTH + 90, 200, s);}//消除當(dāng)前行void DelCurLine(int rowIdx){ //擦除當(dāng)前行 setcolor(BLACK); setfillcolor(BLACK); for (int i = 1; i < xROCK_SQUARE_NUM; ++i) { fillrectangle(WALL_SQUARE_WIDTH + (i - 1)*ROCK_SQUARE_WIDTH, (rowIdx - 1)*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH, WALL_SQUARE_WIDTH + i*ROCK_SQUARE_WIDTH, rowIdx*ROCK_SQUARE_WIDTH + WALL_SQUARE_WIDTH); } //把上面的向下移 int cnt = 0; while (cnt != xROCK_SQUARE_NUM) //直到遇到是空行的為止 { cnt = 0; for (int i = 1; i <= xROCK_SQUARE_NUM; i++) { game_board[rowIdx][i] = game_board[rowIdx - 1][i]; //擦除上面的一行 setcolor(BLACK); setfillcolor(BLACK); fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1) - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i, WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*(rowIdx - 1)); //顯示下面的一行 if (game_board[rowIdx][i] == 1) { setcolor(WHITE); setfillcolor(RED); fillrectangle(WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx - ROCK_SQUARE_WIDTH , WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*i, WALL_SQUARE_WIDTH + ROCK_SQUARE_WIDTH*rowIdx); } if (game_board[rowIdx][i] == 0) cnt++; //統(tǒng)計(jì)一行是不是 都是空格 }//for rowIdx--; }}//是否可以移動(dòng)方塊bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction){ int mask; int rockX; int rockY; rockX = currentLocatePtr->left; rockY = currentLocatePtr->top; mask = (unsigned short)1 << 15; for (int i = 1; i <= 16; i++) { //與掩碼相與為1的 即為方塊上的點(diǎn) if ((RockArray[rockIndex].rockShapeBits & mask) != 0) { //判斷能否移動(dòng)(即掃描即將移動(dòng)的位置 是否與設(shè)置的圍墻有重疊) //若是向上(即翻滾變形) if (f_direction == DIRECT_UP) { //因?yàn)榇饲闆r下傳入的是下一個(gè)方塊的形狀,故我們直接判斷此方塊的位置是否已經(jīng)被占 //判斷下一個(gè)方塊 if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] [(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1) return false; } //如果是向下方向移動(dòng) else if (f_direction == DIRECT_DOWN) { if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 2] [(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] == 1) return false; } else //如果是左右方向移動(dòng) { //f_direction的DIRECT_LEFT為-1,DIRECT_RIGHT為1,故直接加f_direction即可判斷。 if (game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] [(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1 + f_direction] == 1) return false; } } //每4次 換行 轉(zhuǎn)到下一行繼續(xù) i % 4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left) : rockX += ROCK_SQUARE_WIDTH; mask >>= 1; } return true;}//給游戲game_board設(shè)置標(biāo)記表示已經(jīng)占了void SetGameBoardFlag(int rockIdx, RockLocation_t* curRockLocation){ int mask; int rockX; int rockY; rockX = curRockLocation->left; rockY = curRockLocation->top; mask = (unsigned int)1 << 15; for (int i = 1; i <= 16; i++) { //與掩碼相與為1的 即為方塊上的點(diǎn) if ((RockArray[rockIdx].rockShapeBits & mask) != 0) { game_board[(rockY - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] [(rockX - WALL_SQUARE_WIDTH) / ROCK_SQUARE_WIDTH + 1] = 1; } //每4次 換行 轉(zhuǎn)到下一行繼續(xù)畫 i % 4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = curRockLocation->left) : rockX += ROCK_SQUARE_WIDTH; mask >>= 1; }}//判斷游戲是否結(jié)束bool IsGameOver(){ bool topLineHaveRock = false;//頂行是否有方塊 bool bottomLineHaveRock = false; for (int i = 1; i < xROCK_SQUARE_NUM; ++i) { if (game_board[1][i] == 1) topLineHaveRock = true; if (game_board[yROCK_SQUARE_NUM][i] == 1) bottomLineHaveRock = true; } if (bottomLineHaveRock && topLineHaveRock) return true; else return false;}main.cpp
#include"Head.h"#include"Draw.h"#include"Init.h"#include"game.h"int main(){ initgraph(WINDOW_WIDTH,WINDOW_HIGH); DrawGameWindow(); //使用 API 函數(shù)修改窗口名稱 HWND hWnd = GetHWnd(); SetWindowText(hWnd, _T("俄羅斯方塊")); InitGame(); PlayGame(); getchar(); closegraph(); system("pause"); return 0;}配置文件:RockShape.ini
@###@###@@######@@@#@###########@@###@###@########@#@@@#########****#@###@##@@######@###@@@#########@@##@###@#######@@@###@#########****#@##@@@#########@###@@##@#######@@@##@###########@##@@###@######****#@##@@##@#######@@###@@#########****@###@@###@#######@@#@@##########****@###@###@###@###@@@@############****@@##@@##########****
更多關(guān)于俄羅斯方塊的文章,請(qǐng)點(diǎn)擊查看專題:《俄羅斯方塊》
以上就是本文的全部內(nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持武林網(wǎng)。
新聞熱點(diǎn)
疑難解答
圖片精選