<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
每個方塊的朝向使用二維陣列表示
可以直接拷貝執行
#include<graphics.h> #include<stdio.h> #include<time.h> #include<conio.h> //kbhit() int score = 0; //總分 int rank = 0; //等級 #define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5 #define UNIT_SIZE 20 //小方塊寬度 #define START_X 130 //方塊降落框,方塊降落起始位置 #define START_Y 30 #define KEY_UP 87 //使用者操作 #define KEY_LEFT 65 #define KEY_RIGHT 68 #define KEY_DOWN 83 #define KEY_SPACE 32 #define MinX 30 //遊戲左上角位置 #define MinY 30 int speed = 500; //方塊降落速度 int NextIndex = -1; //下一個方塊 int BlockIndex = -1; //當前方塊 typedef enum { //方塊朝向 BLOCK_UP, BLOCK_RIGHT, BLOCK_LEFT, BLOCK_DOWN }block_dir_t; typedef enum { //方塊移動方向 MOVE_DOWN, MOVE_LEFT, MOVE_RIGHT }move_dir_t; //方塊顏色 int color[BLOCK_COUNT] = { GREEN, CYAN, MAGENTA, YELLOW, BROWN }; int visit[30][15]; //存取陣列visit[i][j] = 1表示該位置有方塊 int markColor[30][15]; //對應位置顏色 int block[BLOCK_COUNT * 4][BLOCK_WIDTH][BLOCK_HEIGHT] = { // | 形方塊 { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, // L 形方塊 { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, // 田 形方塊 { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, // T 形方塊 { 0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, // Z 形方塊 { 0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, }; /*************************** * 功能:歡迎頁面 * 輸入: * 無 * 返回: * 無 **************************/ void welcome() { //1.初始化畫布 initgraph(550, 660); system("pause"); //2.設定視窗標題 HWND window = GetHWnd();//獲得視窗,獲得當前視窗 SetWindowText(window, _T("俄羅斯方塊 小明來嘍")); //設定標題 //3.設定遊戲初始頁面 setfont(40, 0, _T("微軟雅黑")); //設定文字的字型樣式(高,寬(0表示自適應),字型) setcolor(WHITE); // 設定顏色 outtextxy(205, 200, _T("俄羅斯方法")); setfont(20, 0, _T("楷體")); setcolor(WHITE); // 設定顏色 outtextxy(175, 300, _T("程式設計,從俄羅斯方塊開始")); Sleep(3000); } /*************************** * 功能:初始化遊戲場景 * 輸入: * 無 * 返回: * 無 **************************/ void initGameSceen() { char str[16]; //存放分數 //1.清屏 cleardevice(); //2.畫場景 rectangle(27, 27, 336, 635); //方塊降落框外框 rectangle(29, 29, 334, 633); //方塊降落框內框 rectangle(370, 50, 515, 195); //方塊提示框 setfont(24, 0, _T("楷體")); //寫「下一個」 setcolor(LIGHTGRAY); //灰色 outtextxy(405, 215, _T("下一個:")); setcolor(RED); //寫分數 outtextxy(405, 280, _T("分數:")); //按指定格式,將score寫入str sprintf_s(str, 16, "%d", score); //這裡設定字元集為多字元,保證outtextxy可以寫出變數str outtextxy(415, 310, str); outtextxy(405, 375, _T("等級:")); //等級 //按指定格式,將rank寫入str sprintf_s(str, 16, "%d", rank); //這裡設定字元集為多字元,保證outtextxy可以寫出變數str outtextxy(415, 405, str); setcolor(LIGHTBLUE); //操作說明 outtextxy(390, 475, "操作說明:"); outtextxy(390, 500, "↑: 旋轉"); outtextxy(390, 525, "↓: 下降"); outtextxy(390, 550, "←: 左移"); outtextxy(390, 575, "→: 右移"); outtextxy(390, 600, "空格: 暫停"); } /***************************************** * 功能:清空方塊提示框裡的方塊 * 輸入: * 無 * 返回: * 無 ****************************************/ void clearBlock() { setcolor(BLACK); setfont(23, 0, "楷體"); for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { int x = 391 + j * UNIT_SIZE; int y = 71 + i * UNIT_SIZE; outtextxy(x, y, "■"); } } } /***************************************** * 功能:清除降落過程中的方塊 * 輸入: * x,y - 方塊的座標(二維陣列左上角位置) * block_dir_t - 方塊方向 * 返回: * 無 ****************************************/ void clearBlock(int x, int y, block_dir_t blockDir) { setcolor(BLACK); // setfont(23, 0, "楷體"); int id = BlockIndex * 4 + blockDir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } /***************************************** * 功能:在提示框 與 降落框的起始位置畫方塊 * 輸入: * x,y - 方塊的座標(二維陣列左上角位置) * 返回: * 無 ****************************************/ void drawBlock(int x, int y) { setcolor(color[NextIndex]); setfont(23, 0, "楷體"); for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[NextIndex * 4][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } /***************************************** *功能:繪製下降過程中的方塊 *輸入: * x,y - 方塊的座標(二維陣列左上角位置) * block_dir_t - 方塊方向 * 返回: * 無 ****************************************/ void drawBlock(int x, int y, block_dir_t dir) { setcolor(color[BlockIndex]); setfont(23, 0, "楷體"); int id = BlockIndex * 4 + dir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { //擦除該方塊的第i行第j列 outtextxy(x + j * UNIT_SIZE, y + i * UNIT_SIZE, "■"); } } } } /***************************************** *功能:方塊提示框中產生新方塊 *輸入: * 無 *返回: * 無 ****************************************/ void nextblock() { clearBlock(); //產生亂數,隨機選擇方塊 srand((unsigned)time(NULL)); //使用時間函數的返回值,來作為隨機種子 NextIndex = rand() % BLOCK_COUNT; //產生0~5的亂數 drawBlock(391, 71); } /***************************************** *功能:判斷在指定位置向指定方向是否可以移動 *輸入: * x,y - 方塊位置 * moveDir - 下一步想要移動的方向 * blockDir - 當前方塊的方向 * 返回: * true - 可以移動 * false - 不可以移動 ****************************************/ bool moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) { //計算方塊左上角在30×15的遊戲區位置(第多少行, 第多少列) int x = (y0 - MinY) / UNIT_SIZE; int y = (x0 - MinX) / UNIT_SIZE; int ret = 1; int id = BlockIndex * 4 + blockDir; if (moveDir == MOVE_DOWN) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向下不能運動的條件:實心方塊已經達到底部(x+i+1==30),或者底部已有方塊 if (block[id][i][j] == 1 && (x + i + 1 == 30 || visit[x + i + 1][y + j] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_LEFT) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向左不能運動的條件:實心方塊已經達到左邊界(y+j==0),或者左邊已有方塊 if (block[id][i][j] == 1 && (y + j <= 0 || visit[x + i][y + j - 1] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_RIGHT) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向下不能運動的條件:實心方塊已經達到右邊界(y+j+1>=15),或者右邊已有方塊 if (block[id][i][j] == 1 && (y + j + 1 >= 15 || visit[x + i][y + j + 1] == 1)) { ret = 0; } } } } return ret; } /***************************** *功能:檢測遊戲是否結束 *輸入: * 無 * 返回: * 無 *****************************/ void failCheck() { //遊戲結束條件是頂部新被繪製出的方塊就要「固化」,頂部新繪製的方塊方向朝上,運動方向朝下 if (!moveable(START_X, START_Y, MOVE_DOWN, (block_dir_t)BLOCK_UP)) { setcolor(WHITE); setfont(45, 0, "隸體"); outtextxy(75, 300, "Game Over!"); Sleep(1000); system("pause"); closegraph(); exit(0); } } /************************** * 功能:延時等待 * 輸入: * * 返回: * 無 *************************/ void wait(int interval) { int count = interval / 10; for (int i = 0; i < count; ++i) { Sleep(10); //如果休眠期間使用者有按鍵,則結束休眠 if (_kbhit()) { return; } } } /***************************************** * 功能:判斷當前方塊是否可以向指定方向旋轉 * 輸入: * x,y - 方塊位置(二維陣列座標) * dir - 方塊旋轉方向 * 返回: * true - 可以旋轉 * false - 不可以旋轉 ****************************************/ bool rotatable(int x, int y, block_dir_t dir) { //首先判斷是否可以繼續向下移動 if (!moveable(x, y, MOVE_DOWN, dir)) { return false; } int x2 = (y - MinY) / UNIT_SIZE; int y2 = (x - MinX) / UNIT_SIZE; int id = BlockIndex * 4 + dir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //不能旋轉條件:左右邊界越界或者已有方塊「阻擋」 if (block[id][i][j] == 1 && (y2 + j < 0 || y2 + j >= 15 || visit[x2 + i][y2 + j] == 1)) { return false; } } } return true; } /***************************************** * 功能: * 輸入: * * 返回: * 無 ****************************************/ void mark(int x, int y, block_dir_t dir) { int id = BlockIndex * 4 + dir; int x2 = (y - MinY) / UNIT_SIZE; int y2 = (x - MinX) / UNIT_SIZE; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { visit[x2 + i][y2 + j] = 1; markColor[x2 + i][y2 + j] = color[BlockIndex]; } } } } /***************************************** * 功能:讀取使用者操作,時時更新降落的方塊 * 輸入: * 無 * 返回: * 無 ****************************************/ void move() { int x = START_X; //方塊起始位置 int y = START_Y; int k = 0; block_dir_t blockDir = (block_dir_t)BLOCK_UP; int curSpeed = speed; //定義當前方塊降落速度 //讀取使用者操作前判斷遊戲是否結束 failCheck(); //持續向下降落 while (1) { int curSpeed = speed; //定義當前方塊降落速度 //清除方塊 clearBlock(x, k + y, blockDir); //判斷選擇的方向 if (_kbhit()) { int key = _getch(); if (key == KEY_SPACE) { system("pause"); } else if (key == KEY_UP) { block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4); if (rotatable(x, y + k, nextDir)) { blockDir = nextDir; } } else if (key == KEY_LEFT) { if (moveable(x, y + k + 20, MOVE_LEFT, blockDir)) { x -= UNIT_SIZE; } } else if (key == KEY_RIGHT) { if (moveable(x, y + k + 20, MOVE_RIGHT, blockDir)) { x += UNIT_SIZE; } } else if (key == KEY_DOWN) { curSpeed = 50; } } k += 20; //繪製方塊 drawBlock(x, y + k, blockDir); //休眠 wait(curSpeed); //方塊的固化處理,方塊固定後結束迴圈,當前一個方塊的move執行完畢 if (!moveable(x, y + k, MOVE_DOWN, blockDir)) { mark(x, y + k, blockDir); break; } } } /***************************************** *功能:繪製剛從頂部降落的方塊,更新提示框內的方塊,呼叫方塊降落函數move() *輸入: * 無 * 返回: * 無 ****************************************/ void newblock() { BlockIndex = NextIndex; //繪製剛從頂部下降的方塊 drawBlock(START_X, START_Y); //讓新出現方塊暫停一會 Sleep(200); //右上角區域繪製下一個方塊 nextblock(); //方塊降落 move(); } /***************************************** * 功能:消除第i行,並把上面的行都往下移 * 輸入: * 無 * 返回: * 無 ****************************************/ void down(int x) { for (int i = x; i > 0; --i) { for (int j = 0; j < 15; ++j) { if (visit[i - 1][j] == 1) { visit[i][j] = 1; markColor[i][j] = markColor[i - 1][j]; setcolor(markColor[i][j]); outtextxy(20 * j + MinX, 20 * i + MinY, "■"); } else { visit[i][j] = 0; setcolor(BLACK); outtextxy(20 * j + MinX, 20 * i + MinY, "■"); } } } //清除最頂層方格 setcolor(BLACK); for (int j = 0; j < 15; ++j) { visit[0][j] = 0; outtextxy(20 * j + MinX, MinY, "■"); } } /***************************************** * 功能:更新分數 * 輸入: * 無 * 返回: * 無 ****************************************/ void addScore(int lines) { char str[32]; score += lines * 10; sprintf_s(str, 32, "%d", score); setcolor(RED); outtextxy(415, 310, str); } /************************* * 功能:更新等級 * 輸入: * 無 * 返回: * 無 *************************/ void updateGrade() { //更新等級 //假設50分一級 rank = score / 50; char str[32]; sprintf_s(str, 32, "%d", rank); setcolor(RED); outtextxy(415, 405, str); //更新速度 if (speed <= 100) { speed = 100; } else { speed = 500 - rank * 20; } } /************************* * 功能:檢查是否有滿行方塊 * 輸入: * 無 * 返回: * 無 *************************/ void check() { int i, j; int clearLines = 0; for (i = 29; i >= 0; i--) { // 檢查第i行有沒有滿 for (j = 0; j < 15 && visit[i][j]; j++); //執行到此處時,有兩種情況: // 1. 第i行沒有滿,即表示有空位 此時 j<15 // 2. 第i行已滿了,此時 j>=15 if (j >= 15) { // 此時,第i行已經滿了,就需要消除第i行 down(i); //消除第i行,並把上面的行都下移 i++; // 因為最外層的迴圈中有 i--, 所以我們先i++, 使得下次迴圈時,再把這一行檢查一下 clearLines++; } } // 更新分數 addScore(clearLines); // 更新等級(更新等級提示,更新速度) updateGrade(); } int main() { welcome(); initGameSceen(); //產生新方塊 nextblock(); // system("pause"); Sleep(800); //初始化存取陣列 memset(visit, 0, sizeof(visit)); while (1) { newblock(); //消除滿行,並更新分數和速度 check(); } system("pause"); closegraph(); return 0; }
1)安裝VS2019,或VS其他版本
2)安裝easyX圖形庫
在遊戲開始前會有一個遊戲歡迎頁面,整個頁面會持續大概三秒,之後便進入遊戲場景。在遊戲歡迎頁面中,除了將顯示遊戲名稱外,還要修改視窗標題。
/*************************** * 功能:歡迎頁面 * 輸入: * 無 * 返回: * 無 **************************/ void welcome() { //1.初始化畫布 initgraph(550, 660); //2.設定視窗標題 HWND window = GetHWnd();//獲得視窗,獲得當前視窗 SetWindowText(window, _T("俄羅斯方塊 小明來嘍")); //設定標題 //3.設定遊戲初始頁面 setfont(40, 0, _T("微軟雅黑")); //設定文字的字型樣式(高,寬(0表示自適應),字型) setcolor(WHITE); // 設定顏色 outtextxy(205, 200, _T("俄羅斯方法")); setfont(20, 0, _T("楷體")); setcolor(WHITE); // 設定顏色 outtextxy(175, 300, _T("程式設計,從俄羅斯方塊開始")); Sleep(3000); }
繪製遊戲場景
/*************************** * 功能:初始化遊戲場景 * 輸入: * 無 * 返回: * 無 **************************/ void initGameSceen() { char str[16]; //存放分數 //1.清屏 cleardevice(); //2.畫場景 rectangle(27, 27, 336, 635); //方塊降落框外框 rectangle(29, 29, 334, 633); //方塊降落框內框 rectangle(370, 50, 515, 195); //方塊提示框 setfont(24, 0, _T("楷體")); //寫「下一個」 setcolor(LIGHTGRAY); //灰色 outtextxy(405, 215, _T("下一個:")); setcolor(RED); //寫分數 outtextxy(405, 280, _T("分數:")); //按指定格式,將score寫入str sprintf_s(str, 16, "%d", score); //這裡設定字元集為多字元,保證outtextxy可以寫出變數str outtextxy(415, 310, str); outtextxy(405, 375, _T("等級:")); //等級 //按指定格式,將rank寫入str sprintf_s(str, 16, "%d", rank); //這裡設定字元集為多字元,保證outtextxy可以寫出變數str outtextxy(415, 405, str); setcolor(LIGHTBLUE); //操作說明 outtextxy(390, 475, "操作說明:"); outtextxy(390, 500, "W: 旋轉"); outtextxy(390, 525, "S: 下降"); outtextxy(390, 550, "A: 左移"); outtextxy(390, 575, "D: 右移"); outtextxy(390, 600, "空格: 暫停"); system("pause"); }
將每個方塊的朝向用二維陣列表示。此次共設計了五種方塊,每個方塊四種朝向,使用三維陣列儲存每個剛快及其朝向。1代表該點是方格。
#define BLOCK_COUNT 5 #define BLOCK_WIDTH 5 #define BLOCK_HEIGHT 5 int block[BLOCK_COUNT * 4][BLOCK_WIDTH][BLOCK_HEIGHT] = { // | 形方塊 { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, // L 形方塊 { 0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, // 田 形方塊 { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0 }, // T 形方塊 { 0,0,0,0,0,0,1,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, // Z 形方塊 { 0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,1,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0 }, { 0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0 }, };
在方塊提示框中每次生成新方塊由兩個動作組成,首先是擦除方塊,接著是繪製新方塊。
/***************************************** * 功能:清空方塊提示框裡的方塊 * 輸入: * 無 * 返回: * 無 ****************************************/ void clearBlock() { setcolor(BLACK); setfont(23, 0, "楷體"); for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { int x = 391 + j * UNIT_SIZE; int y = 71 + i * UNIT_SIZE; outtextxy(x, y, "■"); } } } /***************************************** * 功能:在提示框 與 降落框的起始位置畫方塊 * 輸入: * x,y - 方塊的座標(二維陣列左上角位置) * 返回: * 無 ****************************************/ void drawBlock(int x, int y) { setcolor(color[NextIndex]); setfont(23, 0, "楷體"); for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[NextIndex * 4][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } } /***************************************** *功能:方塊提示框中產生新方塊 *輸入: * 無 *返回: * 無 ****************************************/ void nextblock() { clearBlock(); //產生亂數,隨機選擇方塊 srand((unsigned)time(NULL)); //使用時間函數的返回值,來作為隨機種子 NextIndex = rand() % BLOCK_COUNT; //產生0~5的亂數 drawBlock(391, 71); }
在遊戲框中每次生成新方塊會進入對新方塊降落處理,等處理完後便會迴圈
int main() { welcome(); initGameSceen(); //產生新方塊 nextblock(); Sleep(800); //初始化存取陣列 memset(visit, 0, sizeof(visit)); while (1) { newblock(); } system("pause"); closegraph(); return 0; } /***************************************** *功能:繪製剛從頂部降落的方塊,更新提示框內的方塊,呼叫方塊降落函數move() *輸入: * 無 * 返回: * 無 ****************************************/ void newblock() { BlockIndex = NextIndex; //繪製剛從頂部下降的方塊 drawBlock(START_X, START_Y); //讓新出現方塊暫停一會 Sleep(200); //右上角區域繪製下一個方塊 nextblock(); //方塊降落 move(); }
使用者操作框架:斷遊戲是否結束 → 擦除當前方塊 → 使用者按鍵操作 → 繪製新的方塊 → 延時等待 → 方塊是否要固化(固化則則表明對當前方塊操作結束)。
#define KEY_UP 87 //使用者操作 #define KEY_LEFT 65 #define KEY_RIGHT 68 #define KEY_DOWN 83 #define KEY_SPACE 32 /***************************************** * 功能:讀取使用者操作,時時更新降落的方塊 * 輸入: * 無 * 返回: * 無 ****************************************/ void move() { //讀取使用者操作前判斷遊戲是否結束 failCheck(); //持續向下降落 while (1) { //清除方塊 //to do //判斷選擇的方向 if (_kbhit()) { int key = _getch(); if (key == KEY_SPACE) { //to do } else if (key == KEY_UP) { //to do } else if (key == KEY_LEFT) { //to do } else if (key == KEY_RIGHT) { //to do } else if (key == KEY_DOWN) { //to do } } //繪製方塊 //to do //休眠 //to do //方塊的固化處理,方塊固定後結束迴圈,當前一個方塊的move執行完畢 //to do } }
當新方塊剛從頂部繪製時就碰到了“固化”方塊時則表明遊戲結束,因此我們只需判斷方塊能否向下移動即可。這裡先實現判斷方塊能否向指定方向移動功能。
/***************************************** *功能:判斷在指定位置向指定方向是否可以移動 *輸入: * x,y - 方塊位置 * moveDir - 下一步想要移動的方向 * blockDir - 當前方塊的方向 * 返回: * true - 可以移動 * false - 不可以移動 ****************************************/ bool moveable(int x0, int y0, move_dir_t moveDir, block_dir_t blockDir) { //計算方塊左上角在30×15的遊戲區位置(第多少行, 第多少列) int x = (y0 - MinY) / UNIT_SIZE; int y = (x0 - MinX) / UNIT_SIZE; int ret = 1; int id = BlockIndex * 4 + blockDir; if (moveDir == MOVE_DOWN) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向下不能運動的條件:實心方塊已經達到底部(x+i+1==30),或者底部已有方塊 if (block[id][i][j] == 1 && (x + i + 1 == 30 || visit[x + i + 1][y + j] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_LEFT) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向左不能運動的條件:實心方塊已經達到左邊界(y+j==0),或者左邊已有方塊 if (block[id][i][j] == 1 && (y + j <= 0 || visit[x + i][y + j - 1] == 1)) { ret = 0; } } } } else if (moveDir == MOVE_RIGHT) { for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //向下不能運動的條件:實心方塊已經達到右邊界(y+j+1>=15),或者右邊已有方塊 if (block[id][i][j] == 1 && (y + j + 1 >= 15 || visit[x + i][y + j + 1] == 1)) { ret = 0; } } } } return ret; }
遊戲失敗檢測,當新繪製方塊無法向下移動時則表明遊戲失敗。
/***************************** *功能:檢測遊戲是否結束 *輸入: * 無 * 返回: * 無 *****************************/ void failCheck() { //遊戲結束條件是頂部新被繪製出的方塊就要「固化」,頂部新繪製的方塊方向朝上,運動方向朝下 if (!moveable(START_X, START_Y, MOVE_DOWN, (block_dir_t)BLOCK_UP)) { setcolor(WHITE); setfont(45, 0, "隸體"); outtextxy(75, 300, "Game Over!"); Sleep(1000); system("pause"); closegraph(); exit(0); } }
如果遊戲未失敗,則表明使用者可以繼續操作,在讀取使用者操作前要先將降落框內的方塊清除。
/***************************************** * 功能:清除降落過程中的方塊 * 輸入: * x,y - 方塊的座標(二維陣列左上角位置) * block_dir_t - 方塊方向 * 返回: * 無 ****************************************/ void clearBlock(int x, int y, block_dir_t blockDir) { setcolor(BLACK); // setfont(23, 0, "楷體"); int id = BlockIndex * 4 + blockDir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { int x2 = x + j * UNIT_SIZE; int y2 = y + i * UNIT_SIZE; outtextxy(x2, y2, "■"); } } } }
如果方塊在待轉方向可以向下運動則表明方塊可以旋轉,因此這裡只需少加利用moveable函數即可實現。
/***************************************** * 功能:判斷當前方塊是否可以向指定方向旋轉 * 輸入: * x,y - 方塊位置(二維陣列座標) * dir - 方塊旋轉方向 * 返回: * true - 可以旋轉 * false - 不可以旋轉 ****************************************/ bool rotatable(int x, int y, block_dir_t dir) { //首先判斷是否可以繼續向下移動 if (!moveable(x, y, MOVE_DOWN, dir)) { return false; } int x2 = (y - MinY) / UNIT_SIZE; int y2 = (x - MinX) / UNIT_SIZE; int id = BlockIndex * 4 + dir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { //不能旋轉條件:左右邊界越界或者已有方塊「阻擋」 if (block[id][i][j] == 1 && (y2 + j < 0 || y2 + j >= 15 || visit[x2 + i][y2 + j] == 1)) { return false; } } } return true; }
每次根據使用者操作繪製新的方塊
/***************************************** *功能:繪製下降過程中的方塊 *輸入: * x,y - 方塊的座標(二維陣列左上角位置) * block_dir_t - 方塊方向 * 返回: * 無 ****************************************/ void drawBlock(int x, int y, block_dir_t dir) { setcolor(color[BlockIndex]); setfont(23, 0, "楷體"); int id = BlockIndex * 4 + dir; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { //擦除該方塊的第i行第j列 outtextxy(x + j * UNIT_SIZE, y + i * UNIT_SIZE, "■"); } } } }
每次 處理完使用者操作後會進入延時等待,等待時長會根據當前方塊降落速度而定,在延時等待期間如果檢測到使用者有按鍵操作時則會結束等待。
/************************** * 功能:延時等待 * 輸入: * * 返回: * 無 *************************/ void wait(int interval) { int count = interval / 10; for (int i = 0; i < count; ++i) { Sleep(10); //如果休眠期間使用者有按鍵,則結束休眠 if (_kbhit()) { return; } } }
每次繪製出新方塊後判斷方塊是否還能繼續移動,如果不能移動則表明方塊需要固化。
/***************************************** * 功能:方塊固定 * 輸入: * x,y - 方塊座標 * dir - 方塊朝向 * 返回: * 無 ****************************************/ void mark(int x, int y, block_dir_t dir) { int id = BlockIndex * 4 + dir; int x2 = (y - MinY) / UNIT_SIZE; int y2 = (x - MinX) / UNIT_SIZE; for (int i = 0; i < BLOCK_HEIGHT; ++i) { for (int j = 0; j < BLOCK_WIDTH; ++j) { if (block[id][i][j] == 1) { visit[x2 + i][y2 + j] = 1; markColor[x2 + i][y2 + j] = color[BlockIndex]; } } } }
將上述實現功能補充到操作框架中
void move() { int x = START_X; //方塊起始位置 int y = START_Y; int k = 0; block_dir_t blockDir = (block_dir_t)BLOCK_UP; int curSpeed = speed; //定義當前方塊降落速度 //讀取使用者操作前判斷遊戲是否結束 failCheck(); //持續向下降落 while (1) { int curSpeed = speed; //定義當前方塊降落速度 //清除方塊 clearBlock(x, k + y, blockDir); //判斷選擇的方向 if (_kbhit()) { int key = _getch(); if (key == KEY_SPACE) { system("pause"); } else if (key == KEY_UP) { block_dir_t nextDir = (block_dir_t)((blockDir + 1) % 4); if (rotatable(x, y + k, nextDir)) { blockDir = nextDir; } } else if (key == KEY_LEFT) { if (moveable(x, y + k + 20, MOVE_LEFT, blockDir)) { x -= UNIT_SIZE; } } else if (key == KEY_RIGHT) { if (moveable(x, y + k + 20, MOVE_RIGHT, blockDir)) { x += UNIT_SIZE; } } else if (key == KEY_DOWN) { curSpeed = 50; } } k += 20; //繪製方塊 drawBlock(x, y + k, blockDir); //休眠 wait(curSpeed); //方塊的固化處理,方塊固定後結束迴圈,當前一個方塊的move執行完畢 if (!moveable(x, y + k, MOVE_DOWN, blockDir)) { mark(x, y + k, blockDir); break; } } }
當對一個方塊下降操作結束後,在已固化方塊陣列裡查詢“滿行”方塊,如果存在“滿行”方塊則要進行清除操作,接著更新使用者分數和等級。
/************************ * 功能:檢查是否有滿行方塊 * 輸入: * 無 * 返回: * 無 *************************/ void check() { int i, j; int clearLines = 0; for (i = 29; i >= 0; i--) { // 檢查第i行有沒有滿 for (j = 0; j < 15 && visit[i][j]; j++); //執行到此處時,有兩種情況: // 1. 第i行沒有滿,即表示有空位 此時 j<15 // 2. 第i行已滿了,此時 j>=15 if (j >= 15) { // 此時,第i行已經滿了,就需要消除第i行 down(i); //消除第i行,並把上面的行都下移 i++; // 因為最外層的迴圈中有 i--, 所以我們先i++, 使得下次迴圈時,再把這一行檢查一下 clearLines++; } } // 更新分數 addScore(clearLines); // 更新等級(更新等級提示,更新速度) updateGrade(); } /***************************************** * 功能:消除第i行,並把上面的行都往下移 * 輸入: * 無 * 返回: * 無 ****************************************/ void down(int x) { for (int i = x; i > 0; --i) { for (int j = 0; j < 15; ++j) { if (visit[i - 1][j] == 1) { visit[i][j] = 1; markColor[i][j] = markColor[i - 1][j]; setcolor(markColor[i][j]); outtextxy(20 * j + MinX, 20 * i + MinY, "■"); } else { visit[i][j] = 0; setcolor(BLACK); outtextxy(20 * j + MinX, 20 * i + MinY, "■"); } } } //清除最頂層方格 setcolor(BLACK); for (int j = 0; j < 15; ++j) { visit[0][j] = 0; outtextxy(20 * j + MinX, MinY, "■"); } }
根據清除方塊行數更新使用者分數和等級。
/***************************************** * 功能:更新分數 * 輸入: * 無 * 返回: * 無 ****************************************/ void addScore(int lines) { char str[32]; score += lines * 10; sprintf_s(str, 32, "%d", score); setcolor(RED); outtextxy(415, 310, str); } /************************* * 功能:更新等級 * 輸入: * 無 * 返回: * 無 *************************/ void updateGrade() { //更新等級 //假設50分一級 rank = score / 50; char str[32]; sprintf_s(str, 32, "%d", rank); setcolor(RED); outtextxy(415, 405, str); //更新速度 if (speed <= 100) { speed = 100; } else { speed = 500 - rank * 20; } }
程式碼整合執行
使用easyX繪圖,匯入遊戲圖片,從而使得遊戲效果更為逼真
遊戲戰績的儲存
操作控制略有卡頓
以上就是C/C++實現俄羅斯方塊遊戲的詳細內容,更多關於C/C++ 俄羅斯方塊的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45