C++控制台实现俄罗斯方块游戏

 更新时间:2020年4月25日 17:27  点击:1662

之前学了些C++的课程,一直想着说编点小游戏,可是MFC又不想学,所以就只能变成控制台的小游戏。

俄罗斯方块一定是很多人小时候玩过的游戏。接下来就说说设计想法。

主要实现,选择游戏的等级,加速下降,不同形状不同颜色,暂停和退出功能。

首先是类的设计。

class Box 
{ 
  private: 
    int map[23][12];//画面坐标,记录有方块的点,也是游戏界面 
    int hotpoint[2];//当前活动的点,所有图形都是以此为基准绘制的 
    int top;//当前最高位置 
    int point;//分数 
    int level;//等级 
    int ID;//当前活动图形的ID号 
    int colorID;//图形的颜色ID。 
  public: 
    Box()//初始化 
    { 
      int i,j; 
      for(i=0;i<23;i++) 
        for(j=0;j<12;j++) 
          map[i][j]=0; 
      hotpoint[0]=0; 
      hotpoint[1]=5; 
      point=0; 
      level=1; 
      top=99; 
      ID=0; 
    } 
    void SetColor(int color);//颜色 
    void DrawMap();//画游戏的大界面 
    bool Judge(int x,int y);//判断当前位置能否绘制图形 
    void Welcome();//欢迎界面 
    void DrawBox(int x,int y,int num);//绘制图形 
    void Redraw(int x,int y,int num);//擦除图形 
    void Run();//运行 
    void Turn();//转动方块 
    void UpdataMap();//更新画面 
    void Pause();//暂停 
}; 

接下来就是一些常量和光标函数,便于保存和调用 

#define A1 0//A代表长条型,B为方块,C为L型,D为闪电型 
#define A2 1 
 
 
#define B 2 
 
 
#define C11 3 
#define C12 4 
#define C13 5 
#define C14 6 
 
 
#define C21 7 
#define C22 8 
#define C23 9 
#define C24 10 
 
 
#define D11 11 
#define D12 12 
 
 
#define D21 13 
#define D22 14 
 
 
void SetPos(int i,int j)//设定光标位置 
{ 
COORD pos={i,j}; 
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos); 
} 
 
 
const int sharp[15][8]= 
{ 
{0,0,1,0,2,0,3,0},{0,0,0,1,0,2,0,3}, 
{0,0,1,0,0,1,1,1}, 
{0,0,1,0,1,1,1,2},{0,1,1,1,2,0,2,1},{0,0,0,1,0,2,1,2},{0,0,0,1,1,0,2,0}, 
{1,0,1,1,1,2,0,2},{0,0,0,1,1,1,2,1},{0,0,0,1,0,2,1,0},{0,0,1,0,2,0,2,1}, 
{0,0,0,1,1,1,1,2},{0,1,1,0,1,1,2,0}, 
{0,1,0,2,1,0,1,1},{0,0,1,0,1,1,2,1} 
};//形状点的各个坐标,先纵后横 
 
 
const int high[15]={4,1,2,2,3,2,3,2,3,2,3,2,3,2,3};//这个数组是用来保存各个形状高度的,以上面的坐标相对应 

类方法的实现 

void Box::SetColor(int colorID) 
{ 
  int n_color; 
  switch(colorID) 
  { 
    case 0: n_color = 0x08;break; 
    case 1: n_color = 0x0C;break; 
    case 2: n_color = 0x0D;break; 
    case 3: n_color = 0x0E;break; 
    case 4: n_color = 0x0A;break; 
  } 
  SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n_color); 
} 
void Box::DrawMap()//画界面 
{ 
  int i; 
 
  SetColor(0);//界面颜色 
 
  for(i=0;i<14;i++) 
  { 
     SetPos(i*2,0); 
     cout<<"■"; 
  } 
  for(i=1;i<=24;i++) 
  { 
    SetPos(0,i); 
    cout<<"■"; 
    SetPos(13*2,i); 
    cout<<"■"; 
  } 
  for(i=0;i<14;i++) 
  { 
     SetPos(i*2,24); 
     cout<<"■"; 
  } 
   
  i=15; 
  for(i=15;i<=25;i++) 
  { 
     SetPos(i*2,0); 
     cout<<"■"; 
  } 
  for(i=1;i<=8;i++) 
  { 
    SetPos(15*2,i); 
    cout<<"■"; 
    SetPos(25*2,i); 
    cout<<"■"; 
  } 
  for(i=15;i<=25;i++) 
  { 
     SetPos(i*2,9); 
     cout<<"■"; 
  } 
 
  SetPos(16*2,16); 
  cout<<"俄罗斯方块"; 
  SetPos(16*2,17); 
  cout<<"分数:"<<point; 
  SetPos(16*2,18); 
  cout<<"级别:"<<level; 
} 
 
void Box::DrawBox(int x,int y,int num)//绘制图形 
{ 
   int i; 
   int nx,ny; 
   if (num<2)SetColor(1);//0、1是长条 
   else if(num<3) SetColor(2);//2 方块 
   else if(num<11) SetColor(3);//3、4、5、6、7、8、9、10 
   else SetColor(4); 
   for(i=0;i<4;i++) 
  {  
    nx=x+sharp[num][i*2]; 
    ny=y+sharp[num][i*2+1]; 
    SetPos((ny+1)*2,nx+1);//利用sharp数组相对于点x,y绘制形状 
    //SetColor(i+1); 
    cout<<"■"; 
  } 
} 
 
void Box::Redraw(int x,int y,int num)//擦除图形,原理同上 
{ 
   int i; 
   int nx,ny; 
   for(i=0;i<4;i++) 
  {  
    nx=x+sharp[num][i*2]; 
    ny=y+sharp[num][i*2+1]; 
    SetPos((ny+1)*2,nx+1); 
    cout<<" "; 
  } 
} 
 
void Box::Turn()//转动图形,单纯的该ID而已 
{ 
  switch(ID) 
  { 
    case A1: ID=A2; break; 
    case A2: ID=A1; break; 
 
    case B: ID=B; break; 
 
    case C11: ID=C12; break; 
    case C12: ID=C13; break; 
    case C13: ID=C14; break; 
    case C14: ID=C11; break; 
 
    case C21: ID=C22; break; 
    case C22: ID=C23; break; 
    case C23: ID=C24; break; 
    case C24: ID=C21; break; 
     
    case D11: ID=D12; break; 
    case D12: ID=D11; break; 
 
    case D21: ID=D22; break; 
    case D22: ID=D21; break; 
  } 
 
} 
 
void Box::Welcome()//欢迎界面 
{ 
  char x; 
  while(1) 
  { 
   system("cls"); 
   cout<<"■■■■■■■■■■■■■■■■■■■"<<endl; 
   cout<<"■    俄罗斯方块控制台版    ■"<<endl; 
   cout<<"■■■■■■■■■■■■■■■■■■■"<<endl; 
   cout<<"■   A,D左右移动 S向下加速    ■"<<endl; 
   cout<<"■   W 转动方块  P暂停游戏    ■"<<endl; 
   cout<<"■      Q退出游戏       ■"<<endl; 
   cout<<"■■■■■■■■■■■■■■■■■■■"<<endl; 
   cout<<"■                 ■"<<endl; 
   cout<<"■    按1-9选择等级!!     ■"<<endl; 
   cout<<"■                 ■"<<endl; 
   cout<<"■                 ■"<<endl; 
   cout<<"■■■■■■■■■■■■■■■■■■■"<<endl; 
   SetPos(16,9); 
   x=getch(); 
   if(x<='9'&&x>='1')//设置等级 
   { 
     level=x-'0'; 
     break; 
   } 
  } 
} 
 
void Box::UpdataMap()//更新画面(关键) 
{ 
   int clear; 
   int i,j,k; 
   int nx,ny; 
   int flag; 
   for(i=0;i<4;i++)//更新map数组的信息 
   {  
    nx=hotpoint[0]+sharp[ID][i*2]; 
    ny=hotpoint[1]+sharp[ID][i*2+1]; 
    map[nx][ny]=1; 
   } 
   if(hotpoint[0]<top)//如果热点高于顶点则更新顶点,这里0表示的是纵向的 
     top=hotpoint[0]; 
   clear=0;//消除的格数 
   for(i=hotpoint[0];i<hotpoint[0]+high[ID];i++) 
   { 
     flag=0; 
     for(j=0;j<12;j++)//检测是否可以消除此行 
     { 
       if(map[i][j]==0)//代表有空格,不能消除 
       { 
         flag=1;//1表示不能消除 
         break; 
       } 
     } 
     if(flag==0)//可以消除 
     { 
       for(k=i;k>=top;k--)//从当前位置向上所有的点下移一行 
       { 
         if(k==0)//最高点特殊处理 
           for(j=0;j<12;j++) 
           { 
             map[k][j]=0; 
             SetPos((j+1)*2,k+1); 
             cout<<" "; 
           } 
         else 
         { 
           for(j=0;j<12;j++) 
           { 
             map[k][j]=map[k-1][j]; 
             SetPos((j+1)*2,k+1); 
             if(map[k][j]==0) 
              cout<<" "; 
             else 
              cout<<"■"; 
           } 
         } 
       } 
       top++;//消除成功,最高点下移 
       clear++; 
       point+=clear*10*level; 
     } 
   } 
   SetColor(0); 
   SetPos(16*2,17); 
    cout<<"分数:"<<point; 
} 
 
void Box::Run()//运行游戏 
{ 
  int i=0; 
  char x; 
  int Count;//计数器 
  int nextID; 
  int temp; 
  srand((int)time(0));//将随机数的起点设置为time(0):不带秒 
  ID=rand()%15;//随机生成ID和下一个ID 
  nextID=rand()%15;//这里为了方便,其实每个形状不是等概率生成的 
  DrawBox(hotpoint[0],hotpoint[1],ID);//绘制图形 
  DrawBox(3,17,nextID); 
  Count=1000-level*100;//等级决定计数,这里是用Count控制时间,来控制下落的速度 
  while(1) 
  { 
    if(i>=Count) 
    { 
      i=0;//计数器清零 
      if(Judge(hotpoint[0]+1,hotpoint[1]))//如果下个位置无效(即到底) 
      { 
         UpdataMap();//更新画面 
         ID=nextID;//生成新ID,用原等待ID替换为当前ID 
         hotpoint[0]=0;//热点更新 
         hotpoint[1]=5; 
         Redraw(3,17,nextID); 
         nextID=rand()%15; 
         DrawBox(hotpoint[0],hotpoint[1],ID); 
         DrawBox(3,17,nextID); 
         if(Judge(hotpoint[0],hotpoint[1]))//无法绘制开始图形,游戏结束 
         { 
           //getch(); 
           system("cls"); 
           SetPos(25,15); 
           cout<<"游戏结束!!!最终得分为:"<<point<<endl; 
           system("pause");//就是在命令行上输出一行类似于“Press  any  key  to  exit” 
           exit(0);//关闭所有文件,退出正在执行的程序,返回0代表正常结束 
         } 
      } 
      else 
      { 
        Redraw(hotpoint[0],hotpoint[1],ID);//没有到底,方块下移一位 
        hotpoint[0]++;//热点下移 
        DrawBox(hotpoint[0],hotpoint[1],ID); 
      } 
    } 
    if(kbhit())//读取键盘信息 
    { 
      x=getch(); 
      if(x=='a'||x=='A')//左移 
      { 
         if(Judge(hotpoint[0],hotpoint[1]-1)==0) 
         { 
           Redraw(hotpoint[0],hotpoint[1],ID); 
           hotpoint[1]-=1; 
           DrawBox(hotpoint[0],hotpoint[1],ID); 
         } 
      } 
      if(x=='d'||x=='D')//右移 
      { 
         if(Judge(hotpoint[0],hotpoint[1]+1)==0) 
         { 
           Redraw(hotpoint[0],hotpoint[1],ID); 
           hotpoint[1]+=1; 
           DrawBox(hotpoint[0],hotpoint[1],ID); 
         } 
      } 
      if(x=='s'||x=='S')//向下加速!!!!!!!!此处可以改进,可以改进加速效果。改成+3之后,会出现BUG,最后几个无法加速 
      { 
         if(Judge(hotpoint[0]+3,hotpoint[1])==0) 
         { 
           Redraw(hotpoint[0],hotpoint[1],ID); 
           hotpoint[0]+=1; 
           DrawBox(hotpoint[0],hotpoint[1],ID); 
         } 
      } 
      if(x=='w'||x=='W')//转动方块 
      { 
        temp=ID; 
        Turn(); 
        if(!Judge(hotpoint[0],hotpoint[1])) 
         { 
           Redraw(hotpoint[0],hotpoint[1],temp); 
           DrawBox(hotpoint[0],hotpoint[1],ID); 
         } 
        else 
          ID=temp; 
      } 
      if(x=='p'||x=='P') 
      { 
        //getch(); 
        //system("cls"); 
        Pause(); 
      } 
      if(x=='q'||x=='Q') 
      { 
        system("cls"); 
        SetPos(25,15); 
        cout<<"游戏结束!!!最终得分为:"<<point<<endl; 
        system("pause"); 
        exit(0); 
      } 
      while(kbhit())//读掉剩下的键盘信息 
        getch(); 
    } 
    Sleep(1);//等待1毫秒 
    i++;//计数器加1 
  } 
} 
 
int Box::Judge(int x,int y)//判断当前是否可以绘制方块 
{ 
  int i; 
  int nx,ny; 
  for(i=0;i<4;i++) 
  {  
    nx=x+sharp[ID][i*2]; 
    ny=y+sharp[ID][i*2+1]; 
    if(nx<0||nx>=23||ny<0||ny>=12||map[nx][ny]==1)//不能,返回1 
      return 1; 
  } 
  return 0; 
} 
void Box::Pause() 
{ 
  system("cls"); 
  while(1) 
  {   
    SetPos(30,13); 
    cout<<"暂停等待,咖啡时间^-^"<<endl; 
    if(getch()=='p'||getch()=='P') 
      break; 
  } 
  SetPos(30,13); 
  cout<<"              "<<endl; 
  DrawMap(); 
  int i ,j; 
  for(i=0;i<23;i++) 
    for(j=0;j<12;j++) 
      if(map[i][j]==1) 
      {   
        SetPos((j+1)*2,i+1); 
        cout<<"■"; 
      } 
} 

void main()//主函数 
{ 
  Box game; 
  game.Welcome(); 
  system("cls"); 
  game.DrawMap(); 
  game.Run(); 
} 

待改进的点: 

1、加速下降的时候,从代码中也可以发现,最后几格没法加速。 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持猪先飞。

[!--infotagslink--]

相关文章

  • C++ STL标准库std::vector的使用详解

    vector是表示可以改变大小的数组的序列容器,本文主要介绍了C++STL标准库std::vector的使用详解,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2022-03-06
  • C++中取余运算的实现

    这篇文章主要介绍了C++中取余运算的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ string常用截取字符串方法

    这篇文章主要介绍了C++ string常用截取字符串方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++调用C#的DLL程序实现方法

    本文通过例子,讲述了C++调用C#的DLL程序的方法,作出了以下总结,下面就让我们一起来学习吧。...2020-06-25
  • C++中四种加密算法之AES源代码

    本篇文章主要介绍了C++中四种加密算法之AES源代码,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...2020-04-25
  • C++ 整数拆分方法详解

    整数拆分,指把一个整数分解成若干个整数的和。本文重点给大家介绍C++ 整数拆分方法详解,非常不错,感兴趣的朋友一起学习吧...2020-04-25
  • C++中 Sort函数详细解析

    这篇文章主要介绍了C++中Sort函数详细解析,sort函数是algorithm库下的一个函数,sort函数是不稳定的,即大小相同的元素在排序后相对顺序可能发生改变...2022-08-18
  • C++万能库头文件在vs中的安装步骤(图文)

    这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
  • 详解C++ bitset用法

    这篇文章主要介绍了C++ bitset用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++ Eigen库计算矩阵特征值及特征向量

    这篇文章主要为大家详细介绍了C++ Eigen库计算矩阵特征值及特征向量,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2020-04-25
  • 浅谈C++中的string 类型占几个字节

    本篇文章小编并不是为大家讲解string类型的用法,而是讲解我个人比较好奇的问题,就是string 类型占几个字节...2020-04-25
  • C++ pair的用法实例详解

    这篇文章主要介绍了C++ pair的用法实例详解的相关资料,需要的朋友可以参考下...2020-04-25
  • VSCode C++多文件编译的简单使用方法

    这篇文章主要介绍了VSCode C++多文件编译的简单使用方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-29
  • C++中的循环引用

    虽然C++11引入了智能指针的,但是开发人员在与内存的斗争问题上并没有解放,如果我门实用不当仍然有内存泄漏问题,其中智能指针的循环引用缺陷是最大的问题。下面通过实例代码给大家介绍c++中的循环引用,一起看看吧...2020-04-25
  • C++随机点名生成器实例代码(老师们的福音!)

    这篇文章主要给大家介绍了关于C++随机点名生成器的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • C++如何删除map容器中指定值的元素详解

    map容器是C++ STL中的重要一员,删除map容器中value为指定元素的问题是我们经常与遇到的一个问题,下面这篇文章主要给大家介绍了关于利用C++如何删除map容器中指定值的元素的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。...2020-04-25
  • C++ 约瑟夫环问题案例详解

    这篇文章主要介绍了C++ 约瑟夫环问题案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...2021-08-15
  • C++中cin的用法详细

    这篇文章主要介绍了C++中cin的用法详细,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-04-25
  • 基于C++中常见编译错误的总结详解

    本篇文章是对C++中的常见编译错误进行了详细的分析介绍,需要的朋友参考下...2020-04-25
  • C++实现递归函数的方法

    在本篇内容里小编给大家分享了关于C++实现递归函数的教学步骤,需要的朋友跟着参考下。...2020-04-25