C++实现俄罗斯方块(附代码)

简介: C++实现俄罗斯方块(附代码)

俄罗斯方块


  还记得俄罗斯方块吗?相信这是小时候我们每个人都喜欢玩的一个小游戏。顾名思义,俄罗斯方块自然是俄罗斯人发明的。这人叫阿列克谢·帕基特诺夫。他设置这个游戏的规则是:由小方块组成的不同形状的板块陆续从屏幕上方落下来,玩家通过调整板块的位置和方向,使它们在屏幕底部拼出完整的一条或几条。这些完整的横条会随即消失,给新落下来的板块腾出空间,与此同时,玩家得到分数奖励。没有被消除掉的方块不断堆积起来,一旦堆到屏幕顶端,玩家便告输,游戏结束。

1479e27a68f73696237635ae3927920e.jpg

实现思路


       那么问题就来了,如何用我们学过的C++去实现这个游戏呢?其实在写代码的时候,我们遵循的一个策略就是“拆分法”,从大的框架去一步步拆解成每个小的部分,然后这每个小的部分你都能用C++去实现它;要是拆分的小部分你还是实现不了,那就继续拆分,知道你能实现为止。比如这个俄罗斯方块的游戏,你的思路应该是这样:

1、画出游戏地图, 并留出下一图形和分数显示的位置

2、图形的建立和颜色

3、图形下落的实现以及上一图形的清除

4、是否能继续下落或变形的检测

5、某一行是否已满需清除以及清除功能与分数更新

实现代码如下


#include<iostream>#include<string>#include<cstdlib>#include<windows.h>#include<ctime>#include<conio.h>#include<cstdio>usingnamespacestd;
classTetris{
private:
intrank;        //游戏难度等级intscore;        // 得分intid;          //图形IDintpoint[2];      //两基点inttop;          //最高点高度public:
Tetris();
voidWelocme();      //首界面voidDrawMap();      //游戏界面voidSetColor(int);    //控制颜色voidDraw(int, int, int);    //画图形voidRun();        //运行游戏voidReDraw(int, int, int);      //清除图形boolJudge(int, int, int);
voidTurn(int);        //旋转voidUpdata();        // 更新界面voidPause();        //游戏暂停voidInput_score();
};
constintsharp[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}
};
constinthigh[15] = { 4,1,2,2,3,2,3,2,3,2,3,2,3,2,3 };
intmap[28][16];
#define a1  0      //条形#define a2  1#define b 2          // 方块#define c1 3          //L形#define c2 4#define c3 5#define c4 6#define d1 7          //T形#define d2 8 #define d3 9#define d4 10#define e1 11        //闪电1形#define e2 12#define f1 13        //闪电2形#define f2 14Tetris::Tetris()        //构造函数, 初始化各个值{
point[0] =0;
point[1] =5;
score=0;
top=25;
}
voidTetris::Turn(intnum)        //旋转函数{
switch (num)
  {
casea1: id=a2; break;          //条形互换casea2: id=a1; break;
caseb: id=b; break;          //方块无法旋转casec1: id=c2; break;          //各种L形互换casec2: id=c3; break;
casec3: id=c4; break;
casec4: id=c1; break;
cased1: id=d2; break;          //各种T形互换cased2: id=d3; break;
cased3: id=d4; break;
cased4: id=d1; break;
casee1: id=e2; break;          //两种闪电形互换casee2: id=e1; break;
casef1: id=f2; break;
casef2: id=f1; break;
  }
}
voidSetPos(inti, intj)      //控制光标位置, 列, 行{
COORDpos= { i,j };
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);
}
voidTetris::Pause()        // 暂停函数{
SetPos(32, 10);
cout<<"游戏暂停!"<<endl;
SetPos(30, 11);
cout<<"你的分数为 "<<score;
chartemp;
while (1)
  {
while (1)
    {
if (_kbhit())
      {
temp=_getch();
break;
      }
    }
if (temp==32)
break;
  }
SetPos(32, 10);          // 清除暂停时显示的信息cout<<"         ";
SetPos(30, 11);
cout<<"              ";
}
voidTetris::Updata()          //更新函数{
inti, flag;
intnx, ny;
for (i=0; i<4; i++)
  {
nx=point[0] +sharp[id][i*2];
ny=point[1] +sharp[id][i*2+1];
SetPos((ny+1) *2, nx+1);
SetColor(0);
cout<<"■";
map[nx][ny] =1;          //界面各个点是否为空的更新  }
if (point[0] <top)
top=point[0];          //最高点的更新for (i=point[0]; i<point[0] +high[id]; i++)      //消除行  {
flag=1;
for (intj=0; j<13; j++)          //判定某一行是否满, 用flag来标记if (map[i][j] ==0)
flag=0;
if (flag==1)
    {
for (intk=i; k>=top; k--)
      {
for (intp=0; p<13; p++)
        {
map[k][p] =map[k-1][p];
SetPos((p+1) *2, k+1);
if (map[k][p] ==1)
cout<<"■";
elsecout<<" ";
        }
      }
score+=10;
Input_score();
    }
  }
}
voidTetris::Input_score()
{
SetColor(3);
SetPos(30, 19);
cout<<"得分: "<<score;
}
voidTetris::Welocme()      //欢迎界面{
SetColor(1);
charx;
while (1)
  {
system("cls");
cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"    俄罗斯方块    "<<endl;
cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"    操作方式:"<<endl;
cout<<"    ↑ - 旋转"<<endl;
cout<<"    ↓ - 加速下移"<<endl;
cout<<"    ← - 左移"<<endl;
cout<<"    → - 右移"<<endl;
cout<<"    空格 - 暂停"<<endl;
cout<<"■■■■■■■■■■■■■■■■■■■■■"<<endl;
cout<<"■ 按1—3选择难度■"<<endl;
SetPos(20, 10);
x=getchar();
if (x<='9'&&x>='0')
    {
rank=x-'0';
break;
    }
  }
}
voidTetris::SetColor(intcolor_num)      //设置颜色{
intn;
switch (color_num)
  {
case0: n=0x08; break;
case1: n=0x0C; break;
case2: n=0x0D; break;
case3: n=0x0E; break;
case4: n=0x0A; break;
  }
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), n);
}
voidTetris::DrawMap()        //画游戏时界面{
inti;
SetColor(0);
for (i=0; i<24; i++)    //宽24格  {
SetPos(i*2, 0);
cout<<"■";
SetPos(i*2, 26);
cout<<"■";
  }
for (i=0; i<26; i++)    //高26格  {
SetPos(0, i);
cout<<"■";
SetPos(28, i);
cout<<"■";
SetPos(46, i);
cout<<"■";
  }
for (i=14; i<24; i++)
  {
SetPos(i*2, 16);
cout<<"■";
  }
SetColor(3);
Input_score();
SetPos(30, 21);
cout<<"难度等级: "<<rank;
SetPos(32, 2);
cout<<"下一图形";
}
voidTetris::Draw(intx, inty, intnum)        //画图形{
intnx, ny;
for (inti=0; i<4; i++)
  {
nx=x+sharp[num][2*i];
ny=y+sharp[num][2*i+1];
SetPos((ny+1) *2, nx+1);
SetColor(i+1);
cout<<"■";
  }
}
voidTetris::ReDraw(intx, inty, intnum)        //为更新图形的位置清除图形{
intnx, ny;
for (inti=0; i<4; i++)
  {
nx=x+sharp[num][2*i];
ny=y+sharp[num][2*i+1];
SetPos((ny+1) *2, nx+1);
cout<<" ";
  }
}
boolTetris::Judge(intx, inty, intnum)        //判定在x, y 所指位置是否可画编号为{                          //num 的图形, 若不可画则反回trueintnx, ny;
for (inti=0; i<4; i++)
  {
nx=x+sharp[num][2*i];
ny=y+sharp[num][2*i+1];
if (!(nx<25&&nx>=0&&ny<13&&ny>=0&&!map[nx][ny]))
returntrue;
  }
returnfalse;
}
voidTetris::Run()          //运行游戏{
intnext_id;
srand((int)time(0));
id=rand() %15;
next_id=rand() %15;
Draw(point[0], point[1], id);
Draw(5, 16, next_id);
intcount;
if (rank==1)
count=150;
elseif (rank==2)
count=100;
elseif (rank==3)
count=50;
elsecount=5;
inti=0;  //不同等级对应不同countwhile (1)
  {
if (!(i<count))        //i 与 count 用于控制时间    {
i=0;
if (Judge(point[0] +1, point[1], id))      //在某一位置不能下落的话      {
Updata();
id=next_id;
ReDraw(5, 16, next_id);
next_id=rand() %15;
point[0] =0; point[1] =5;
Draw(point[0], point[1], id);
Draw(5, 16, next_id);
if (Judge(point[0], point[1], id))
        {
system("cls");
SetPos(20, 10);
cout<<"游戏结束!"<<endl;
SetPos(20, 11);
cout<<"你的分数为 "<<score<<endl;
system("pause");
exit(1);
        }
      }
else//继续下落      {
ReDraw(point[0], point[1], id);
point[0]++;
Draw(point[0], point[1], id);
      }
    }
if (_kbhit())        //键盘输入值时     {
intkey, key2;
key=_getch();
if (key==224)
      {
key2=_getch();
if (key2==72)      //按向上方向键时        {
inttemp=id;
Turn(id);
if (Judge(point[0], point[1], id))
id=temp;
ReDraw(point[0], point[1], temp);
Draw(point[0], point[1], id);
        }
if (key2==80)        //按向下方向键时        {
if (!Judge(point[0] +2, point[1], id))
          {
ReDraw(point[0], point[1], id);
point[0] +=2;
Draw(point[0], point[1], id);
          }
        }
elseif (key2==75)        //按向左方向键时        {
if (!Judge(point[0], point[1] -1, id))
          {
ReDraw(point[0], point[1], id);
point[1]--;
Draw(point[0], point[1], id);
          }
        }
elseif (key2==77)          //按向右方向键时        {
if (!Judge(point[0], point[1] +1, id))
          {
ReDraw(point[0], point[1], id);
point[1]++;
Draw(point[0], point[1], id);
          }
        }
      }
elseif (key==32)          // 按下空格暂停Pause();
    }
Sleep(1);    //等待1毫秒i++;        //控制下落间隔  }
}
intmain()
{
Tetrisgame;
game.Welocme();
system("cls");        //清除欢迎界面game.DrawMap();
game.Run();
}

运行效果如下图所示


a129596493e35472147c93b4d89b5770.png

fc204339a96352a3c5cf93f507a006bf.png

出现的问题


       这个代码还是有一点问题的,如上图所示,需要后续不断改进。粉丝中有看了之后改进好了的,欢迎和我一起交流

相关文章
|
机器学习/深度学习 C++
C++实现实现逆时针旋转矩阵
C++实现实现逆时针旋转矩阵
C++实现实现逆时针旋转矩阵
|
编译器 C++ 容器
【C++要笑着学】迭代器适配器 | 内嵌类型实现反向迭代器 | 迭代器萃取
上一章讲解 list 模拟实现时,我们简单的提到了反向迭代器,我们说反向迭代器其实就是对正向迭代器的一种封装 —— 适配器模式(配接器模式)。当时我们做的是简单的了解,本章我们就来探讨这一部分的知识。
125 1
【C++要笑着学】迭代器适配器 | 内嵌类型实现反向迭代器 | 迭代器萃取
|
存储 C++
C++异常处理机制由浅入深, 以及函数调用汇编过程底层刨析. C++11智能指针底层模拟实现
C++异常处理机制由浅入深, 以及函数调用汇编过程底层刨析. C++11智能指针底层模拟实现
C++异常处理机制由浅入深, 以及函数调用汇编过程底层刨析. C++11智能指针底层模拟实现
|
存储 Linux C语言
生产者消费者模式保姆级教程 (阻塞队列解除耦合性) 一文帮你从C语言版本到C++ 版本, 从理论到实现 (一文足以)
生产者消费者模式保姆级教程 (阻塞队列解除耦合性) 一文帮你从C语言版本到C++ 版本, 从理论到实现 (一文足以)
生产者消费者模式保姆级教程 (阻塞队列解除耦合性) 一文帮你从C语言版本到C++ 版本, 从理论到实现 (一文足以)
|
设计模式 安全 定位技术
C++从面试常考实现特殊类到单例模式的实现
C++从面试常考实现特殊类到单例模式的实现
C++从面试常考实现特殊类到单例模式的实现
|
存储 Java 应用服务中间件
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
线程池设计, 从简单的我们平常设计线程池图解,到生活中的类似线程池的处理现实场景, 到简单的C++模拟nginx写的单链表组织工作队列的简单线程池实现 + nginx 部分源码刨析
如何用c++实现异常处理
如何用c++实现异常处理
如何用c++实现异常处理
|
存储 算法 C++
分块刨析从函数原型到分块实现C++STL(vector)
分块刨析从函数原型到分块实现C++STL(vector)
分块刨析从函数原型到分块实现C++STL(vector)
|
C++
C/C++ Qt Tree与Tab组件实现分页菜单
虽然`TreeWidget`组件可以实现多节点的增删改查,但多节点操作显然很麻烦,在一般的应用场景中基本上只使用一层结构即可解决大部分开发问题,`TreeWidget`组件通常可配合`TabWidget`组件,实现一个类似于树形菜单栏的功能,当用户点击菜单栏中的选项时则会跳转到不同的页面上。
304 0
C/C++ Qt Tree与Tab组件实现分页菜单
|
算法 编译器 C语言
【C++要笑着学】Functor 仿函数 | 模拟实现 stack & queue | 模拟实现优先级队列(二)
在上一章中,我们讲解了STL的栈和队列,本章我们来模拟实现一下它们。在讲解优先级队列的同时我们顺便把上一章提到的仿函数进行一个讲解,使用仿函数可以有效替换使用难以理解的函数指针的场景。我们通过仿函数 less 和 greater 去控制优先级队列的 Compare,从而能同时适配升序和降序。
106 0
【C++要笑着学】Functor 仿函数 | 模拟实现 stack & queue | 模拟实现优先级队列(二)