IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++俄罗斯方块教程 -> 正文阅读

[C++知识库]C++俄罗斯方块教程

资源地址

https://download.csdn.net/download/weixin_45783299/20164763?spm=1001.2014.3001.5503

以下为代码讲解


窗口的设计

游戏窗口类的设计,就是打印一个矩形当成游戏边框

首先写一个光标移动的函数用于操作打印(使用了windows句柄)

void gotoxy(HANDLE hOut, int x, int y)	
{
 COORD pos;
 pos.X = x;   横坐标
 pos.Y = y;   纵坐标
 SetConsoleCursorPosition(hOut, pos);
}
窗口和菜单的设定
	void make_frame()
{

定义显示器句柄变量

HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
打印游戏名称
gotoxy(hOut,FrameX+Frame_width-5,FrameY-2);
	cout << "俄罗斯方块" << endl;
打印选择菜单让玩家知道如何操作
gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7);
cout<<"**********下一个方块:"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13);
cout<<"**********"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+17);
cout<<"↑键:变形"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+19);
cout<<"空格:暂停游戏"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15);
cout<<"Esc :退出游戏"<<endl;
}
制作游戏的边宽
gotoxy(hOut,FrameX,FrameY);     使用前面写的光标移动函数
cout<<"╔"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY);
cout<<"╗"<<endl;
 gotoxy(hOut,FrameX,FrameY+Frame_height);
cout<<"╚"<<endl;
 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height);
cout<<"╝"<<endl;
a[FrameX][FrameY+Frame_height]=2;     
a[FrameX+2*Frame_width-2][FrameY+Frame_height]=2;
for(i=2;i<2*Frame_width-2;i+=2)		FrameX,FrameY	是开始定义的初始坐标,
 {									打印坐标后并将他们存入开始定义的数组中
  打印上横框
  gotoxy(hOut,FrameX+i,FrameY);		
 cout<<"═"<<endl;       
 }
 for(i=2;i<2*Frame_width-2;i+=2)
 {
打印下横框
  gotoxy(hOut,FrameX+i,FrameY+Frame_height);
 cout<<"═"<<endl;   
    
  a[FrameX+i][FrameY+Frame_height]=2;    
 }
 for(i=1;i<Frame_height;i++)
 {
打印左竖框
  gotoxy(hOut,FrameX,FrameY+i); 
 cout<<"║"<<endl;         
  a[FrameX][FrameY+i]=2;    
 }
 for(i=1;i<Frame_height;i++)
 {
打印右竖框
  gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i); 
 cout<<"║"<<endl;        
  a[FrameX+2*Frame_width-2][FrameY+i]=2;  
 }
}

(1)俄罗斯方块类的设计

设计俄罗斯方块的结构体
 	struct Tetris
{
	int x;      中心方块的x轴坐标
	int y;      中心方块的y轴坐标
	int flag;     标记方块类型的序号
	int next;     下一个俄罗斯方块类型的序号
	int speed;     俄罗斯方块移动的速度
	int count;     产生俄罗斯方块的个数
	int score;     游戏的分数
	int level;     游戏的等级
};

根据上面定义的结构创建俄罗斯方块
思路通过笨方法穷举出6大类的总共19种的形状类型

使用到的数组及其作用
int a[80][80]={0};
标记游戏屏幕的图案:2,1,0分别表示该位置为游戏边框、方块、无图案;初始化为无图案
int b[4];    
标记4"口"方块:1表示有方块,0表示无方块
void make_tetris(struct Tetris *tetris)
{
a[tetris->x][tetris->y]=b[0];6大类,19种类型
switch(tetris->flag)            
 {
1.	先制作最简单的田字方块,是由4个小方格组成
 
case 1:
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x+2][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }
2.	然后是由方块组成的直线类 
  case 2:        
   {  
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x+2][tetris->y]=b[2];
    a[tetris->x+4][tetris->y]=b[3];
    break;
   }

直线的垂直状态 
   
case 3:       
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y-2]=b[2];
    a[tetris->x][tetris->y+1]=b[3];
    break;
   }

3.T字形方块类 
  case 4:         
   {  
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x+2][tetris->y]=b[2];
    a[tetris->x][tetris->y+1]=b[3];
   break;
   }
  T字顺时针转90度方块
	case 5:       
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y+1]=b[2];
    a[tetris->x-2][tetris->y]=b[3];
    break;
   }
	T字顺时针转180度方块
  case 6:        
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x-2][tetris->y]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }
	  T字顺时针转270度方块
  case 7:       
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y+1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }

4.Z字方块类 
  case 8:     
   {  
    a[tetris->x][tetris->y+1]=b[1];
    a[tetris->x-2][tetris->y]=b[2];
    a[tetris->x+2][tetris->y+1]=b[3];
    break;
   }

Z字顺时针转90度方块
  case 9:         
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x-2][tetris->y]=b[2];
    a[tetris->x-2][tetris->y+1]=b[3];
    break;
   }
Z字顺时针转180度方块
  case 10:        
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x-2][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }
Z字顺时针转270度方块
  case 11:       
   {  
    a[tetris->x][tetris->y+1]=b[1];
    a[tetris->x+2][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }

  7字方块类 
  case 12:      
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y+1]=b[2];
    a[tetris->x-2][tetris->y-1]=b[3];
    break;
   }
  7字顺时针转90度方块
  case 13:      
   {  
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x-2][tetris->y+1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }
7字顺时针转180度方块
  case 14:       
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y+1]=b[2];
    a[tetris->x+2][tetris->y+1]=b[3];
    break;
   }
7字顺时针转270度方块
  case 15:       
   {
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x+2][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }7字方块
  case 16:    
   { 
    a[tetris->x][tetris->y+1]=b[1];
    a[tetris->x][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y-1]=b[3];
    break;
   }7字顺指针转90度方块
  case 17:        
   { 
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x-2][tetris->y-1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }7字顺时针转180度方块
  case 18:       
   {  
    a[tetris->x][tetris->y-1]=b[1];
    a[tetris->x][tetris->y+1]=b[2];
    a[tetris->x-2][tetris->y+1]=b[3];
    break;
   }7字顺时针转270度方块
  case 19:       
   {  
    a[tetris->x-2][tetris->y]=b[1];
    a[tetris->x+2][tetris->y+1]=b[2];
    a[tetris->x+2][tetris->y]=b[3];
    break;
   }

↑以前就是6种形状的不同状态的穷举

有了所需样式后,接下来的方法是让方块动起来
int if_moveable(struct Tetris *tetris)
写个判断当中心方块位置上有图案时,返回值为0,即不可移动
if(a[tetris->x][tetris->y]!=0) 
 {
  return 0;
 }
 else
 {
当为田字方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
  if(
   ( tetris->flag==1  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   或为直线方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
   ( tetris->flag==2  && ( a[tetris->x-2][tetris->y]==0   && 
    a[tetris->x+2][tetris->y]==0 && a[tetris->x+4][tetris->y]==0 ) )   ||
   ( tetris->flag==3  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y-2]==0 && a[tetris->x][tetris->y+1]==0 ) )   ||
   ( tetris->flag==4  && ( a[tetris->x-2][tetris->y]==0   &&
    a[tetris->x+2][tetris->y]==0 && a[tetris->x][tetris->y+1]==0 ) )   ||
   ( tetris->flag==5  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y]==0 ) )   ||
   ( tetris->flag==6  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 ) )   ||
   ( tetris->flag==7  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) )   ||
   ( tetris->flag==8  && ( a[tetris->x][tetris->y+1]==0   &&
    a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
   ( tetris->flag==9  && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
   ( tetris->flag==10 && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   ( tetris->flag==11 && ( a[tetris->x][tetris->y+1]==0   &&
    a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   ( tetris->flag==12 && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y-1]==0 ) ) ||
   ( tetris->flag==13 && ( a[tetris->x-2][tetris->y]==0   &&
    a[tetris->x-2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   ( tetris->flag==14 && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
   ( tetris->flag==15 && ( a[tetris->x-2][tetris->y]==0   &&
    a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   ( tetris->flag==16 && ( a[tetris->x][tetris->y+1]==0   &&
    a[tetris->x][tetris->y-1]==0 && a[tetris->x+2][tetris->y-1]==0 ) ) ||
   ( tetris->flag==17 && ( a[tetris->x-2][tetris->y]==0   &&
    a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
   ( tetris->flag==18 && ( a[tetris->x][tetris->y-1]==0   &&
    a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
   ( tetris->flag==19 && ( a[tetris->x-2][tetris->y]==0   &&
    a[tetris->x+2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) )
   {
    return 1;
   }
 }
 return 0;
}

为了增加游戏的可玩性,将出现的方块设置为随机类的随机形状
void get_flag(struct Tetris *tetris):Tetris是之前定义的俄罗斯方块结构体的名字
{
记住产生方块的个数
 tetris->count++;     
初始化随机数种子
 srand((unsigned)time(NULL));  
 if(tetris->count==1)
 {
记住第一个方块的序号
  tetris->flag = rand()%19+1;  
 }
记住下一个方块的序号
 tetris->next = rand()%19+1;   
}

将方块打印至方框
void print_tetris(HANDLE hOut,struct Tetris *tetris)
{
 for(i=0;i<4;i++)
 {
  b[i]=1;: 标记4"口"方块:1表示有方块,0表示无方块
 }
制作俄罗斯方块
 make_tetris(tetris);      
 for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
 {
  for(j=tetris->y-2;j<=tetris->y+1;j++)
  {
   if( a[i][j]==1 && j>FrameY )
   {
    gotoxy(hOut,i,j);
   cout<<"□"<<endl;    
   }
  }
打印菜单信息
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+1);
cout<<"level : "<<tetris->level<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+3);
cout<<"score :"<<tetris->score<<endl;
 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+5);
cout<<"speed :"<<tetris->speed<<"ms"<<endl;
 }


当方框内方块成一行我们要进行消除,故做一个删除函数为之后的使用
void clear_tetris(HANDLE hOut,struct Tetris *tetris)
{
 for(i=0;i<4;i++)
 {
  b[i]=0;: 标记4"口"方块:1表示有方块,0表示无方块
 }
 make_tetris(tetris);     
 for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
 {
  for(j=tetris->y-2;j<=tetris->y+1;j++)
  {
   if( a[i][j]==0 && j>FrameY )
   {
清除方块
    gotoxy(hOut,i,j);
   cout<<"  "<<endl;    
   }
  }
 }
}

判断是否满行并删除满行的俄罗斯方块
void del_full(HANDLE hOut,struct Tetris *tetris)
{       当某行有Frame_width-2个方块时,则满行
 int k,del_count=0;
  分别用于记录某行方块的个数和删除方块的行数的变量
 for(j=FrameY+Frame_height-1;j>=FrameY+1;j--)
 {
  k=0;
  for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)
  {  
   if(a[i][j]==1) 竖坐标依次从下往上,横坐标依次由左至右判断是否满行
   {
    k++;  记录此行方块的个数
    if(k==Frame_width-2)
    {
     for(k=FrameX+2;k<FrameX+2*Frame_width-2;k+=2)
     {  
删除满行的方块
      a[k][j]=0;
      gotoxy(hOut,k,j);
      cout<<"  "<<endl;
      Sleep(1);
     }
     for(k=j-1;k>FrameY;k--)
     {  
如果删除行以上的位置有方块,则先清除,再将方块下移一个位置
      for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)
      {
       if(a[i][k]==1)
       {
        a[i][k]=0;
        gotoxy(hOut,i,k);
        cout<<"  "<<endl;
        a[i][k+1]=1;
        gotoxy(hOut,i,k+1);
        cout<<"□"<<endl;
       }
      }
     }
     j++;   
方块下移后,重新判断删除行是否满行
记录删除方块的行数
     del_count++; 
    }
   }
  }
 }
 每删除一行,得100分
tetris->score+=100*del_count; 
 if( del_count>0 && ( tetris->score%1000==0 || tetris->score/1000>tetris->level-1 ) )
 {        
如果得1000分即累计删除10行,速度加快20ms并升一级
  tetris->speed-=20;
  tetris->level++;
 }
}

开始游戏
void start_game()
{
 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);  定义显示器句柄变量
 struct Tetris t,*tetris=&t;       定义结构体的指针并指向结构体变量
 unsigned char ch;         定义接收键盘输入的变量
 tetris->count=0;      初始化俄罗斯方块数为0个
 tetris->speed=400;    初始移动速度为400ms
 tetris->score=0;      初始游戏的分数为0分
 tetris->level=1;      初始游戏为第1while(1)
{
循环产生方块,直至游戏结束
得到产生俄罗斯方块类型的序号
  get_flag(tetris);    
 记住当前俄罗斯方块序号
  temp=tetris->flag;   
  打印下一个俄罗斯方块的图形(右边窗口)
  tetris->x=FrameX+2*Frame_width+6;
  tetris->y=FrameY+10;
  tetris->flag = tetris->next;
  print_tetris(hOut,tetris);
  tetris->x=FrameX+Frame_width;  初始中心方块x坐标
  tetris->y=FrameY-1;     初始中心方块y坐标
  tetris->flag=temp;     取出当前的俄罗斯方块序号
  while(1)
  { 
控制方块方向,直至方块不再下移
   label:print_tetris(hOut,tetris); 打印俄罗斯方块
   Sleep(tetris->speed);    延缓时间
   clear_tetris(hOut,tetris);   清除痕迹
   temp1=tetris->x;     记住中心方块横坐标的值
   temp2=tetris->flag;     记住当前俄罗斯方块序号
   if(kbhit())   
   {         判断是否有键盘输入,有则用ch↓接收
    ch=getch(); 
    if(ch==75)      按←键则向左动,中心横坐标减2
    {      
     tetris->x-=2;
    }
    if(ch==77)      按→键则向右动,中心横坐标加2
    {      
     tetris->x+=2;    
    }
    if(ch==72)      按↑键则变体即当前方块顺时针转90{      
     if( tetris->flag>=2 && tetris->flag<=3 )
     {
      tetris->flag++; 
      tetris->flag%=2;
      tetris->flag+=2;
     }
     if( tetris->flag>=4 && tetris->flag<=7 )
     {
      tetris->flag++;
      tetris->flag%=4;
      tetris->flag+=4;
     }    
     if( tetris->flag>=8 && tetris->flag<=11 )
     {
      tetris->flag++;
      tetris->flag%=4;
      tetris->flag+=8;
     }    
     if( tetris->flag>=12 && tetris->flag<=15 )
     {
      tetris->flag++;
      tetris->flag%=4;
      tetris->flag+=12;
     }    
     if( tetris->flag>=16 && tetris->flag<=19 )
     {
      tetris->flag++;
      tetris->flag%=4;
      tetris->flag+=16;
     }
    }
    if(ch==27){
    	system("cls");
        cout<<"退出游戏成功!"<<endl;
        getch();
	    exit(0);   退出游戏 
        break;
	}
    if(ch==32)      按空格键,暂停
    {
     print_tetris(hOut,tetris);
     while(1)
     {
      if(kbhit())    再按空格键,继续游戏
      {
       ch=getch();
       if(ch==32)
       {
        goto label;
       }
      }
     }
    }
    if(if_moveable(tetris)==0)  如果不可动,上面操作无效
    {
     tetris->x=temp1;
     tetris->flag=temp2;
    }
    else       如果可动,执行操作
    {
     goto label;
    }
   }
   tetris->y++;      如果没有操作指令,方块向下移动
   if(if_moveable(tetris)==0)   如果向下移动且不可动,方块放在此处
   {    
    tetris->y--;
    print_tetris(hOut,tetris);
    del_full(hOut,tetris);
    break;
   }
  }
  for(i=tetris->y-2;i<tetris->y+2;i++)
  { 
游戏结束条件:方块触到框顶位置
   if(i==FrameY)
   {
    j=0;       如果游戏结束,j=0
   }
  }
  if(j==0)       
  {
  	
   system("cls");
   cout<<"Game Over!"<<endl;
   getch();
   break;
  }
   清除下一个俄罗斯方块的图形(右边窗口)
  tetris->flag = tetris->next;
  tetris->x=FrameX+2*Frame_width+6;
  tetris->y=FrameY+10;
  clear_tetris(hOut,tetris);  
 }
}
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-07-11 16:27:42  更:2021-07-11 16:29:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年4日历 -2024/4/29 1:07:44-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码