俄罗斯方块的 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个点,最后一个参数是颜色,这个是红色高亮,如图:

俄罗斯方块的 C++实现_第1张图片

然后用一个数组保存所有图形的高度,消除的时候需要用到高度,上面长条的高度就是1。

下面是代码,定义的时候每个形状的初始状态标号分别为0,1,2,3,4,5,6,变换的形状为7--18,先是头文件,Tetris.h:

[cpp]  view plain copy
  1. #ifndef TETRIS_H_  
  2. #define TETRIS_H_  
  3. #include   
  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++)"white-space:pre">     //初始化地图  
  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();         "white-space:pre">    //绘制地图  
  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  
下面就是包含所有形状的二维数组,最后一个数是颜色,还有包含每个形状的高度的数组:
[cpp]  view plain copy
  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 };  //数组是用来保存上面每个一维数组的各个形状高度的  
设定光标位置的函数,同时设定输出的颜色:
[cpp]  view plain copy
  1. void setCurPos(int i, int j, int color = 1 | 2 | 4) 
  2. {                           "white-space:pre">    //color相当于自己选择颜色,没有就用默认的白色  
  3.     HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE);       //获得标准输出句柄  
  4.     SetConsoleTextAttribute(out, color);"white-space:pre">            //设置颜色  
  5.     COORD pos = { i * 2, j };  
  6.     SetConsoleCursorPosition(out, pos);"white-space:pre">         //设置位置  
  7. }  
下面是画地图的函数,地图是长12,宽23的地图,然后用白块做一圈外围,外围比地图大1,下面是代码:
[cpp]  view plain copy
  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. }  
下面是画方块和消除方块的函数:
[cpp]  view plain copy
  1. void tetris::DrawBox(int x, int y, int id)"white-space:pre">      //画方块  
  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);"white-space:pre">   "font-family: Arial, Helvetica, sans-serif;">//玩的地图比实际的地图横纵坐标都大1(因为有一个外围)  
  10.        cout << "■";  
  11.     }  
  12. }  
  13. void tetris::ReBox(int x, int y, int id)"white-space:pre">        //消除方块  
  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);"white-space:pre">        
  21.         cout << " ";  
  22.     }  
  23. }  
下面是判断是否可以完成想要的操作,比如下降,翻转,x、y是当前热点的坐标,然后根据当前坐标加上每种图形的四个点,全都没有超界或者没有方块,就可以做操作:
[cpp]  view plain copy
  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:

[cpp]  view plain copy
  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. }  
下面是更新地图,当有方块落到最底下时,检查下落方块的高度范围内是否可以消行,如果可以就消除:

[cpp]  view plain copy
  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)"white-space:pre">           //因为地图的最上面是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)         "white-space:pre">    //没有可以消除的  
  20.             {  
  21.                 flag = 1;  
  22.                 break;  
  23.             }  
  24.         }  
  25.         if (flag == 0)                      //可以消除当前行  
  26.         {  
  27.             for (int k = j; k >= top; k--)"white-space:pre">           //将每一行的上一行下移,直到最高点所在行下移完毕  
  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++;                  "white-space:pre">    //消除成功,最高点下降一个  
  56.             clear++;  
  57.             score += clear * 100;  
  58.         }  
  59.     }  
  60.     setCurPos(16, 15);  
  61.     cout << " 分数: " << score;  
  62. }  
下面就是运行游戏了,把上面的代码组合一下就好:
[cpp]  view plain copy
  1. void tetris::RunGame()  
  2. {  
  3.     initInterface();  
  4.     system("cls");  
  5.     DrawMap();  
  6.   
  7.     char x = ' ';                   //读取键盘信息  
  8.     int i = 0;      "white-space:pre">           //计时,到时间没有获得指令,自动下降  
  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)  "white-space:pre">        //下个位置无效,到底了  
  24.             {  
  25.                 UpdateMap(curId);                       //更新一下画面  
  26.                 ReBox(17, 3, nextId);               "white-space:pre">       //清除原来的下一个图形  
  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);                 "white-space:pre">    //画上现在的下一个图形  
  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')              "white-space:pre">        //右移  
  61.             {"white-space:pre">             
  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')              "white-space:pre">        //向下加速  
  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')"white-space:pre">                      //变形  
  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函数了:

[cpp]  view plain copy
  1. #include "Tetris.h"  
  2.   
  3. int main()  
  4. {  
  5.     tetris ter;  
  6.     ter.RunGame();  
  7.     return 0;  
  8. }  
最后把上面的连起来就可以运行了,下面是截图:

俄罗斯方块的 C++实现_第2张图片

你可能感兴趣的:(C++)