俄羅斯方塊的 C++實現

源碼下載地址:http://download.csdn.net/detail/lt_lover/9721862

最近想寫一個俄羅斯方塊,正好電腦裏面有個以前下的代碼,於是就看了看思路,然後自己加了一些東西,要是忘了就不好了

先做7個不同類型的方塊,分別爲 長條形、方形、L形、反L形、Z形、反Z形、土字形。用一個二維數組保存每個形狀,每個形狀使用4個點,每個點代表每種形狀的一個小方格,比如:{ 0, 0, 0, 1, 0, 2, 0, 3, FOREGROUND_RED | FOREGROUND_INTENSITY }  就是點(0,0)、(0,1)、(0,2)、(0,3) 4個點,最後一個參數是顏色,這個是紅色高亮,如圖:


然後用一個數組保存所有圖形的高度,消除的時候需要用到高度,上面長條的高度就是1。

下面是代碼,定義的時候每個形狀的初始狀態標號分別爲0,1,2,3,4,5,6,變換的形狀爲7--18,先是頭文件,Tetris.h:

  1. #ifndef TETRIS_H_  
  2. #define TETRIS_H_  
  3. #include <windows.h>  
  4. //長條形  
  5. const int A1 = 0;  
  6. const int A2 = 7;  
  7. //方塊  
  8. const int B = 1;  
  9. //L 形狀  
  10. const int C11 = 2;  
  11. const int C12 = 8;  
  12. const int C13 = 9;  
  13. const int C14 = 10;  
  14. //L 的另一個形狀  
  15. const int C21 = 3;  
  16. const int C22 = 11;  
  17. const int C23 = 12;  
  18. const int C24 = 13;  
  19. //Z 形狀  
  20. const int D11 = 4;  
  21. const int D12 = 14;  
  22. //Z 的另一個形狀  
  23. const int D21 = 5;  
  24. const int D22 = 15;  
  25.   
  26. //土字形  
  27. const int E31 = 6;  
  28. const int E32 = 16;  
  29. const int E33 = 17;  
  30. const int E34 = 18;  
  31.   
  32. class tetris  
  33. {  
  34. private:  
  35.     int map[12][23];        //背景  
  36.     int top;            //當前的最高點  
  37.     int score;          //分數  
  38.     int level;          //難度等級  
  39.     int ID;             //當前的方塊的形狀  
  40.     int hotPoint[2];        //熱點,當前活動的所在點     
  41. public:  
  42.     tetris()  
  43.     {  
  44.         for (int i = 0; i < 12; i++)<span style="white-space:pre">     </span>//初始化地圖  
  45.         for (int j = 0; j < 23; j++)  
  46.             map[i][j] = 0;  
  47.         top = 99;  
  48.         score = 0;  
  49.         level = 1;  
  50.         ID = 0;  
  51.         hotPoint[0] = 5;    //下落起始點的橫座標  
  52.         hotPoint[1] = 0;    //下落起始點的縱座標  
  53.     }  
  54.     void DrawMap();         <span style="white-space:pre">    </span>//繪製地圖  
  55.     void initInterface();           //初始化界面  
  56.     void DrawBox(int x, int y, int id); //繪製圖形  
  57.     void ReBox(int x, int y, int id);   //擦除圖形  
  58.     int  IsJudge(int x, int y, int id); //是否可以繪製圖形  
  59.     int  TurnBlock(int id);         //旋轉方塊  
  60.     void UpdateMap(int id);         //更新畫面  
  61.     void RunGame();             //運行  
  62. };  
  63.   
  64. #endif  
下面就是包含所有形狀的二維數組,最後一個數是顏色,還有包含每個形狀的高度的數組:
  1. int sharp[19][9] =                  //每個一維數組內有8個點,每兩個點是一個 形狀的一個小方格,在4*4的表格中  
  2. {  
  3.     { 0, 0, 0, 1, 0, 2, 0, 3, FOREGROUND_RED | FOREGROUND_INTENSITY },          //長條形  
  4.     { 0, 0, 1, 0, 0, 1, 1, 1, FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY },   //方形  
  5.     { 0, 0, 0, 1, 1, 1, 2, 1, FOREGROUND_GREEN | FOREGROUND_RED },              //L形  
  6.     { 0, 1, 1, 1, 2, 1, 2, 0, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY },  //反L形  
  7.     { 0, 0, 1, 0, 1, 1, 2, 1, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY },    //Z形  
  8.     { 1, 0, 2, 0, 0, 1, 1, 1, FOREGROUND_GREEN | FOREGROUND_INTENSITY },            //反Z形  
  9.     { 0, 0, 0, 1, 0, 2, 1, 1, FOREGROUND_BLUE | FOREGROUND_INTENSITY },     //土形  
  10.     //下面是上面形狀的變換  
  11.     { 0, 0, 1, 0, 2, 0, 3, 0, FOREGROUND_RED | FOREGROUND_INTENSITY },                        
  12.     { 1, 0, 1, 1, 1, 2, 0, 2, FOREGROUND_GREEN | FOREGROUND_RED },  
  13.     { 0, 0, 1, 0, 2, 0, 2, 1, FOREGROUND_GREEN | FOREGROUND_RED },  
  14.     { 0, 0, 1, 0, 0, 1, 0, 2, FOREGROUND_GREEN | FOREGROUND_RED },  
  15.     { 0, 0, 1, 0, 1, 1, 1, 2, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY },  
  16.     { 0, 0, 1, 0, 2, 0, 0, 1, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY },  
  17.     { 0, 0, 0, 1, 0, 2, 1, 2, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY },  
  18.     { 1, 0, 0, 1, 1, 1, 0, 2, FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY },  
  19.     { 0, 0, 0, 1, 1, 1, 1, 2, FOREGROUND_GREEN | FOREGROUND_INTENSITY },  
  20.     { 0, 0, 1, 0, 2, 0, 1, 1, FOREGROUND_BLUE | FOREGROUND_INTENSITY },  
  21.     { 0, 1, 1, 0, 1, 1, 1, 2, FOREGROUND_BLUE | FOREGROUND_INTENSITY },  
  22.     { 1, 0, 0, 1, 1, 1, 2, 1, FOREGROUND_BLUE | FOREGROUND_INTENSITY }  
  23. };  
  24.   
  25. int high[19] = { 4, 2, 2, 2, 2, 2, 3, 1, 3, 2, 3, 3, 2, 3, 3, 3, 2, 3, 2 };  //數組是用來保存上面每個一維數組的各個形狀高度的  
設定光標位置的函數,同時設定輸出的顏色:
  1. void setCurPos(int i, int j, int color = 1 | 2 | 4) 
  2. {                           <span style="white-space:pre">    </span>//color相當於自己選擇顏色,沒有就用默認的白色  
  3.     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);       //獲得標準輸出句柄  
  4.     SetConsoleTextAttribute(out, color);<span style="white-space:pre">            </span>//設置顏色  
  5.     COORD pos = { i * 2, j };  
  6.     SetConsoleCursorPosition(out, pos);<span style="white-space:pre">         </span>//設置位置  
  7. }  
下面是畫地圖的函數,地圖是長12,寬23的地圖,然後用白塊做一圈外圍,外圍比地圖大1,下面是代碼:
  1. void tetris::DrawMap()  
  2. {  
  3.     //地圖框架  
  4.     for (int i = 0; i < 14; i++)     // 0 - 13  
  5.     {  
  6.         setCurPos(i, 0);  
  7.         cout << "■";  
  8.     }  
  9.     for (int i = 0; i < 25; i++) // 0 - 24  
  10.     {  
  11.         setCurPos(0, i);  
  12.         cout << "■";  
  13.         setCurPos(13, i);  
  14.         cout << "■";  
  15.     }  
  16.     for (int i = 0; i < 14; i++)  
  17.     {  
  18.         setCurPos(i, 24);  
  19.         cout << "■";  
  20.     }  
  21.     //信息框架  
  22.     for (int i = 15; i <= 25; i++)  
  23.     {  
  24.         setCurPos(i, 0);  
  25.         cout << "■";  
  26.         setCurPos(i, 8);  
  27.         cout << "■";  
  28.     }  
  29.     for (int i = 0; i <= 8; i++)  
  30.     {  
  31.         setCurPos(15, i);  
  32.         cout << "■";  
  33.         setCurPos(25, i);  
  34.         cout << "■";  
  35.     }  
  36.     setCurPos(16, 12);  
  37.     cout << "俄羅斯方塊(6D)";  
  38.     setCurPos(16, 15);  
  39.     cout << " 分數: " << score;  
  40.     setCurPos(16, 16);  
  41.     cout << " 等級: " << level;  
  42. }  
下面是畫方塊和消除方塊的函數:
  1. void tetris::DrawBox(int x, int y, int id)<span style="white-space:pre">      </span>//畫方塊  
  2. {  
  3.     int nx = 0, ny = 0;  
  4.     int color = sharp[id][8];  
  5.     for (int i = 0; i < 4; i++)  
  6.     {  
  7.         nx = x + sharp[id][i * 2];  
  8.         ny = y + sharp[id][i * 2 + 1];  
  9.         setCurPos(nx + 1, ny + 1, color);<span style="white-space:pre">   </span><span style="font-family: Arial, Helvetica, sans-serif;">//玩的地圖比實際的地圖橫縱座標都大1(因爲有一個外圍)</span><span style="white-space:pre">  
  10. </span>       cout << "■";  
  11.     }  
  12. }  
  13. void tetris::ReBox(int x, int y, int id)<span style="white-space:pre">        </span>//消除方塊  
  14. {  
  15.     int nx = 0, ny = 0;  
  16.     for (int i = 0; i < 4; i++)  
  17.     {  
  18.         nx = x + sharp[id][i * 2];  
  19.         ny = y + sharp[id][i * 2 + 1];  
  20.         setCurPos(nx + 1, ny + 1);<span style="white-space:pre">      </span>  
  21.         cout << " ";  
  22.     }  
  23. }  
下面是判斷是否可以完成想要的操作,比如下降,翻轉,x、y是當前熱點的座標,然後根據當前座標加上每種圖形的四個點,全都沒有超界或者沒有方塊,就可以做操作:
  1. int tetris::IsJudge(int x, int y, int id)  
  2. {  
  3.     int nx = 0, ny = 0;  
  4.     for (int i = 0; i < 4; i++)  
  5.     {  
  6.         nx = x + sharp[id][i * 2];  
  7.         ny = y + sharp[id][i * 2 + 1];  
  8.         if (nx < 0 || nx >= 12 || ny < 0 || ny >= 23 || map[nx][ny] != 0)   //不能放了,返回0  
  9.             return 0;  
  10.     }  
  11.     return 1;  
  12. }  
下面是翻轉方塊的操作,就是改一下方塊id:

  1. int tetris::TurnBlock(int id)  
  2. {  
  3.     switch (id)  
  4.     {  
  5.     case A1: id = A2;  break;  
  6.     case A2: id = A1;  break;  
  7.   
  8.     case B:  id = B;   break;  
  9.   
  10.     case C11:id = C12; break;  
  11.     case C12:id = C13; break;  
  12.     case C13:id = C14; break;  
  13.     case C14:id = C11; break;  
  14.   
  15.     case C21:id = C22; break;  
  16.     case C22:id = C23; break;  
  17.     case C23:id = C24; break;  
  18.     case C24:id = C21; break;  
  19.   
  20.     case D11:id = D12; break;  
  21.     case D12:id = D11; break;  
  22.   
  23.     case D21:id = D22; break;  
  24.     case D22:id = D21; break;  
  25.   
  26.     case E31:id = E32; break;  
  27.     case E32:id = E33; break;  
  28.     case E33:id = E34; break;  
  29.     case E34:id = E31; break;  
  30.     }  
  31.     return id;  
  32. }  
下面是更新地圖,當有方塊落到最底下時,檢查下落方塊的高度範圍內是否可以消行,如果可以就消除:

  1. void tetris::UpdateMap(int id)  
  2. {  
  3.     int nx = 0, ny = 0;  
  4.     int flag;  
  5.     int clear = 0;                          //清除了多少個行,最後積分  
  6.     for (int i = 0; i < 4; i++)  
  7.     {  
  8.         nx = hotPoint[0] + sharp[id][i * 2];  
  9.         ny = hotPoint[1] + sharp[id][i * 2 + 1];  
  10.         map[nx][ny] = sharp[id][8];             //保存顏色值,因爲顏色值不爲0,所以可以和沒有方格區分開  
  11.     }  
  12.     if (hotPoint[1] < top)<span style="white-space:pre">           </span>//因爲地圖的最上面是0,最底層是22,所以當前熱點的y座標如果小於top,就是最高點變化了,更新一下top  
  13.         top = hotPoint[1];  
  14.     for (int j = hotPoint[1]; j < hotPoint[1] + high[id]; j++)   //從上向下進行消除,從下向上容易少消行  
  15.     {  
  16.         flag = 0;  
  17.         for (int i = 0; i < 12; i++)  
  18.         {  
  19.             if (map[i][j] == 0)         <span style="white-space:pre">    </span>//沒有可以消除的  
  20.             {  
  21.                 flag = 1;  
  22.                 break;  
  23.             }  
  24.         }  
  25.         if (flag == 0)                      //可以消除當前行  
  26.         {  
  27.             for (int k = j; k >= top; k--)<span style="white-space:pre">           </span>//將每一行的上一行下移,直到最高點所在行下移完畢  
  28.             {  
  29.                 if (k == 0)             //消除 到了最頂行  
  30.                 {  
  31.                     for (int i = 0; i < 12; i++)  
  32.                     {  
  33.                         map[i][k] = 0;  
  34.                         setCurPos(i + 1, k + 1);  
  35.                         cout << " ";  
  36.                     }  
  37.                 }  
  38.                 else  
  39.                 {  
  40.                     for (int i = 0; i < 12; i++)  
  41.                     {  
  42.                         map[i][k] = map[i][k - 1];  
  43.                         setCurPos(i + 1, k + 1);   //因爲有兩條圖形框邊,遊戲運行過程中的座標系相對於 真正的座標系是x、y都加 1 的  
  44.                         if (map[i][k] == 0)    //被刪除行的 上一行是空的,所以這一行也是空的  
  45.                             cout << " ";  
  46.                         else                        //上一行不是空的  
  47.                         {  
  48.                             int tempColor = map[i][k];  
  49.                             setCurPos(i + 1, k + 1, tempColor);  
  50.                             cout << "■";  
  51.                         }  
  52.                     }  
  53.                 }  
  54.             }  
  55.             top++;                  <span style="white-space:pre">    </span>//消除成功,最高點下降一個  
  56.             clear++;  
  57.             score += clear * 100;  
  58.         }  
  59.     }  
  60.     setCurPos(16, 15);  
  61.     cout << " 分數: " << score;  
  62. }  
下面就是運行遊戲了,把上面的代碼組合一下就好:
  1. void tetris::RunGame()  
  2. {  
  3.     initInterface();  
  4.     system("cls");  
  5.     DrawMap();  
  6.   
  7.     char x = ' ';                   //讀取鍵盤信息  
  8.     int i = 0;      <span style="white-space:pre">    </span>       //計時,到時間沒有獲得指令,自動下降  
  9.     int Count = 0;  
  10.     int nextId = 0;  
  11.     int curId = 0;  
  12.     srand(time(0));  
  13.     curId = rand() % 7;  
  14.     nextId = rand() % 7;  
  15.     DrawBox(hotPoint[0], hotPoint[1], curId);   //畫當前圖形  
  16.     DrawBox(17, 3, nextId);             //畫出下一個要出現的圖形  
  17.     Count = 10000 - 1000 * level;  
  18.     while (1)  
  19.     {  
  20.         if (i >= Count)                                  //可以自動下移了  
  21.         {  
  22.             i = 0;                                  //將 i 清零,下次繼續計數  
  23.             if (IsJudge(hotPoint[0], hotPoint[1] + 1, curId) == 0)  <span style="white-space:pre">        </span>//下個位置無效,到底了  
  24.             {  
  25.                 UpdateMap(curId);                       //更新一下畫面  
  26.                 ReBox(17, 3, nextId);               <span style="white-space:pre">    </span>   //清除原來的下一個圖形  
  27.                 curId = nextId;  
  28.                 nextId = rand() % 7;  
  29.                 hotPoint[0] = 5;                        //更新熱點  
  30.                 hotPoint[1] = 0;  
  31.                 DrawBox(hotPoint[0], hotPoint[1], curId);  
  32.                 DrawBox(17, 3, nextId);                 <span style="white-space:pre">    </span>//畫上現在的下一個圖形  
  33.                 if (IsJudge(hotPoint[0], hotPoint[1], curId) == 0)      //無法繪製當前圖形  
  34.                 {  
  35.                     system("cls");  
  36.                     cout << "遊戲結束!!!最終得分爲:" << score << endl;  
  37.                     system("pause");  
  38.                     exit(0);  
  39.                 }  
  40.             }  
  41.             else  
  42.             {  
  43.                 ReBox(hotPoint[0], hotPoint[1], curId);  
  44.                 hotPoint[1]++;  
  45.                 DrawBox(hotPoint[0], hotPoint[1], curId);  
  46.             }  
  47.         }  
  48.         if (_kbhit())                                   //讀取鍵盤信息  
  49.         {  
  50.             x = _getch();  
  51.             if (x == 'a' || x == 'A')                       //左移  
  52.             {  
  53.                 if (IsJudge(hotPoint[0] - 1, hotPoint[1], curId))  
  54.                 {  
  55.                     ReBox(hotPoint[0], hotPoint[1], curId);  
  56.                     hotPoint[0]--;  
  57.                     DrawBox(hotPoint[0], hotPoint[1], curId);  
  58.                 }  
  59.             }  
  60.             else if (x == 'd' || x == 'D')              <span style="white-space:pre">        </span>//右移  
  61.             {<span style="white-space:pre">           </span>  
  62.                 if (IsJudge(hotPoint[0] + 1, hotPoint[1], curId))  
  63.                 {  
  64.                     ReBox(hotPoint[0], hotPoint[1], curId);  
  65.                     hotPoint[0]++;  
  66.                     DrawBox(hotPoint[0], hotPoint[1], curId);  
  67.                 }  
  68.             }  
  69.             else if (x == 's' || x == 'S')              <span style="white-space:pre">        </span>//向下加速  
  70.             {  
  71.                 if (IsJudge(hotPoint[0], hotPoint[1] + 1, curId))  
  72.                 {  
  73.                     ReBox(hotPoint[0], hotPoint[1], curId);  
  74.                     hotPoint[1]++;  
  75.                     DrawBox(hotPoint[0], hotPoint[1], curId);  
  76.                 }  
  77.             }  
  78.             else if (x == 'w' || x == 'W')<span style="white-space:pre">                      </span>//變形  
  79.             {  
  80.                 int temp = curId;  
  81.                 curId = TurnBlock(curId);  
  82.                 if (IsJudge(hotPoint[0], hotPoint[1], curId))  
  83.                 {  
  84.                     ReBox(hotPoint[0], hotPoint[1], temp);  
  85.                     DrawBox(hotPoint[0], hotPoint[1], curId);  
  86.                 }  
  87.                 else  
  88.                     curId = temp;  
  89.             }  
  90.             else if (x == ' ')                          //暫停  
  91.             {  
  92.                 _getch();  
  93.             }  
  94.             while (_kbhit())                            //讀取掉剩下的鍵盤信息s  
  95.                 _getch();  
  96.         }  
  97.         i++;  
  98.     }  
  99. }  
最後就是main函數了:

  1. #include "Tetris.h"  
  2.   
  3. int main()  
  4. {  
  5.     tetris ter;  
  6.     ter.RunGame();  
  7.     return 0;  
  8. }  
最後把上面的連起來就可以運行了,下面是截圖:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章