主要思路
1.先初始化界面,用一个30*20矩阵来保存界面的每一个位置,包括颜色跟数值,数值0,1,2用来区分是空格还是方块还是墙。
2.再初始化方块,用4*4矩阵保存,初始7个方块,再利用矩阵旋转,得到剩下的21个方块。
3.先判断再运行,保证不会越过墙。如果4*4的方块矩阵下一格是方块就落在上面。
4.一旦一个方块落到底便判断是否构成消除条件,满一行则减掉,未满则生成下一个方块。
5.判断游戏结束:即判断最顶上一行是否有方块**
具体实现
构造界面
窗格中所有的方格均使用"■"构成,先使用双重for循环画出三条线当做墙构造出简要界面,其中左边是游戏界面,右边是显示界面。使用gotoxy函数调整位置一一显示游戏操作说明。
需要的数据结构
dia[][]表示不同的方块,包含一个二维数组,数组储存了方块的形状
face可以表示窗格中每一个位置,其中包含了区分方块和空格的数值和颜色
构造方块
先定义一个临时二维4*4数组tmp备用,先一一定义七个基础方块dia[0][0]到dia[6][0]。再一一将矩阵导入临时二维数组tmp使用[j][k]→[4-k-1][j]的坐标变换实现方块的旋转从而又构造出另外的21个形状(非21种)。
判断运行条件
这个子函数需要四个变量:方块基本类型序号,旋转次数,横坐标和纵坐标。前两者用来确定方块的具体形状,后两者用来确定方块目前在界面中的具体位置。若在界面中[x+i][y+j]被墙或者格子挡住,则方块不能往下运行。若[x+i][y+j]全为空,则可以往下运行。并注意及时清除方块走过的痕迹。
判断消除条件
因为在宏定义中方格为1,所以只需某一行的和为FACE_Y-2即18就可以认为这一行满了,达到了删除的条件。随即将这一行全赋值为空,并将上面的每一行以此往下降。
判断游戏结束条件
当方格停留在最上面一行超过限定时间即可以认为游戏结束。此时输出成绩。
附源代码
#include<stdio.h>
#include<stdlib.h>//包含system()
#include<time.h> //包含以时间为依据的随机数
#include<windows.h>//包含隐藏光标
#include<conio.h>
#define SPACE 32 //ascii码
#define LEFT 75
#define RIGHT 77
#define DOWN 80
#define ESC 27
#define Wall 2 //墙是2
#define Box 1 //方块是1
#define Kong 0 //空是0
#define FACE_X 30
#define FACE_Y 20 //界面尺寸
void gotoxy(int x,int y); //移动光标 声
int color(int c); //颜色 明
void hidden_cursor(); //隐藏光标 函
void inter_face(); //初始化界面 数
void init_dia(); //初始化方块信息 部
void draw_dia(int base,int space_c,int x,int y); //覆盖方块 分
void draw_kong(int base,int space_c,int x,int y); //画方块
int pd(int n,int space_c,int x,int y); //判断是否到底
void start_game(); //开始游戏
int xc();//消除
void read_file(); //读写最高记录
void write_file(); //写最高纪录
int grade=0;//当前分数 定义全局
int nn=0; // 变量
//
void gotoxy(int x,int y) //实现光标控制所在位置
{
COORD coord; //coord为结构体变量成员包含x,y
coord.X=y;
coord.Y=x;
SetConsoleCursorPosition( GetStdHandle( STD_OUTPUT_HANDLE ), coord );
}
//
struct Face
{
int data[FACE_X][FACE_Y+10]; //数值,为1是方块,为0是空格
int color[FACE_X][FACE_Y+10]; //对应方块的颜色
}face;
typedef struct Diamonds
{ int space[4][4]; //4*4矩阵,为1为方块,0为空
}Dia;
Dia dia[7][4]; //一维基础7个方块,二维表示4个旋转次数
int main()/*主函数*/
{
system("cls"); //清屏
system("title 俄罗斯方块");
color(7);//7号为白色
// system("mode con cols=60 lines=30"); //调整系统控制台显示的宽度和高度,高度为30个字符,宽度为60个字符。 非必须,可能会造成混乱。
hidden_cursor();//隐藏光标
srand(time(NULL)); //以现在的系统时间作为随机数的种子来产生随机数
grade=0; //分数记为0
inter_face(); //构造界面
init_dia(); //构造不同种方块
nn=rand()%7; //产生0-6的随机数
while(TRUE) //一直运行除非跳出
{
start_game();
}
return 0;
}
/
void hidden_cursor()//隐藏光标
{
HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO cci;
GetConsoleCursorInfo(hOut,&cci);
cci.bVisible=0; //赋1为显示,赋0为隐藏
SetConsoleCursorInfo(hOut,&cci);
}
/
void inter_face()//构造游戏界面
{ int i,j;
for(i=0;i<FACE_X;i++)
{ for(j=0;j<FACE_Y+10;j++)
{ if(j==0 || j==FACE_Y-1 || j==FACE_Y+9||i==FACE_X-1)
{ face.data[i][j]=Wall;
gotoxy(i,2*j);
printf("■");
}
else
face.data[i][j]=0;
}
}
gotoxy(FACE_X-18,2*FACE_Y+2);
printf("左移:←");
gotoxy(FACE_X-16,2*FACE_Y+2);
printf("右移:→");
gotoxy(FACE_X-14,2*FACE_Y+2);
printf("加速:持续按↓");
gotoxy(FACE_X-12,2*FACE_Y+2);
printf("旋转:空格");
gotoxy(FACE_X-10,2*FACE_Y+2);
printf("暂停: S");
gotoxy(FACE_X-8,2*FACE_Y+2);
printf("退出: ESC");
gotoxy(FACE_X-6,2*FACE_Y+2);
printf("重新开始:R");
gotoxy(FACE_X-4,2*FACE_Y+2);
printf("分数:%d",grade);
}
/
void init_dia() //构造不同种的方块
{
int i,j,k,z;
int tmp[4][4];
for(i=0;i<3;i++)
dia[0][0].space[1][i]=1;
dia[0][0].space[2][1]=1; //┬形
for(i=1;i<4;i++)
dia[1][0].space[i][1]=1;
dia[1][0].space[1][2]=1; //┌形
for(i=1;i<4;i++)
dia[2][0].space[i][2]=1;
dia[2][0].space[1][1]=1; //┐形
for(i=0;i<2;i++)
{ dia[3][0].space[1][i]=1;
dia[3][0].space[2][i+1]=1; //Z形--1
dia[4][0].space[1][i+1]=1;
dia[4][0].space[2][i]=1;//Z形--2(反)
dia[5][0].space[1][i+1]=1;
dia[5][0].space[2][i+1]=1;//田字形
}
for(i=0;i<4;i++)
dia[6][0].space[i][2]=1;//1形
//基础7个形状
for(i=0;i<7;i++)//
{
for(z=0;z<3;z++)//
{
for(j=0;j<4;j++)
{
for(k=0;k<4;k++)
{
tmp[j][k]=dia[i][z].space[j][k];
}
}
for(j=0;j<4;j++)
{
for(k=0;k<4;k++)
{
dia[i][z+1].space[j][k]=tmp[4-k-1][j];
}
}
}
}
//旋转后的21个形状
}
/
void start_game()
{ int n,ch,t=0,x=0,y=FACE_Y/2-2,i,j;
int space_c=0;//旋转次数
draw_kong(nn,space_c,4,FACE_Y+3);
n=nn;
nn=rand()%7; //随机生成下一块
color(nn);
draw_dia(nn,space_c,4,FACE_Y+3);
while(1)
{
color(n);
draw_dia(n,space_c,x,y);//画出图形
if(t==0)
t=20000;//控制下降时间
while(--t)
{ if(kbhit()!=0)//有输入就跳出
break;
}
if(t==0)
{
if(pd(n,space_c,x+1,y)==1)//判断下一行是否能下降
{ draw_kong(n,space_c,x,y);
x++; //向下降落
}
else
{
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(dia[n][space_c].space[i][j]==1)
{
face.data[x+i][y+j]=Box;
face.color[x+i][y+j]=n;
while(xc());
}
}
}
break;
}
}
else
{
ch=getch();
switch(ch) //移动
{
case LEFT: if(pd(n,space_c,x,y-1)==1) //判断是否可以移动
{ draw_kong(n,space_c,x,y);
y--;
}
break;
case RIGHT: if(pd(n,space_c,x,y+1)==1)
{ draw_kong(n,space_c,x,y);
y++;
}
break;
case DOWN: if(pd(n,space_c,x+1,y)==1)
{ draw_kong(n,space_c,x,y);
x++;
}
break;
case SPACE: if(pd(n,(space_c+1)%4,x+1,y)==1)
{ draw_kong(n,space_c,x,y);
space_c=(space_c+1)%4;
}
break;
case ESC : system("cls");
gotoxy(FACE_X/2,FACE_Y);
printf("---游戏结束!---\n\n");
gotoxy(FACE_X/2+2,FACE_Y);
printf("你的分数为:%d",grade);
gotoxy(FACE_X/2+4,FACE_Y);
printf("---按任意键退出!---\n");
getch();
exit(0);
break;
case 'R':
case 'r': main();
// exit(0);
case 'S':
case 's': while(1)
{ if(kbhit()!=0)//有输入就跳出
break;
}
break;
}
}
}
}
int xc()//消除
{
int i,j,k,sum;
for(i=FACE_X-2;i>4;i--)
{
sum=0;
for(j=1;j<FACE_Y-1;j++)
{
sum+=face.data[i][j];
}
if(sum==0)
break;
if(sum==FACE_Y-2) //满一行,减掉
{
grade+=100;
color(8);
gotoxy(FACE_X-4,2*FACE_Y+2);
printf("分数:%d",grade);
for(j=1;j<FACE_Y-1;j++)
{
face.data[i][j]=Kong;
gotoxy(i,2*j);
printf(" ");
}
for(j=i;j>1;j--)
{ sum=0;
for(k=1;k<FACE_Y-1;k++)
{
sum+=face.data[j-1][k]+face.data[j][k];
face.data[j][k]=face.data[j-1][k];
if(face.data[j][k]==Kong)
{
gotoxy(j,2*k);
printf(" ");
}
else
{
gotoxy(j,2*k);
color(face.color[j][k]);
printf("■");//消除之后剩余的方块
}
}
if(sum==0)
return 1;
}
}
}
for(i=1;i<FACE_Y-1;i++)
{
if(face.data[1][i]==Box)
{
char n;
Sleep(10); //延时判断到顶
system("cls");
color(7);
gotoxy(FACE_X/2-2,2*(FACE_Y/3));
printf("你的分数为:%d",grade);
gotoxy(FACE_X/2,2*(FACE_Y/3));
printf("GAME OVER!\n");
do
{
gotoxy(FACE_X/2+2,2*(FACE_Y/3));
printf("是否重新开始游戏(y/n): ");
scanf("%c",&n);
gotoxy(FACE_X/2+4,2*(FACE_Y/3));
if(n!='n' && n!='N' && n!='y' && n!='Y')
printf("输入错误,请重新输入!");
else
break;
}while(1);
if(n=='n' || n=='N')
{
gotoxy(FACE_X/2+4,2*(FACE_Y/3));
printf("按任意键退出游戏!");
exit(0);
}
else if(n=='y' || n=='Y')
main();
}
}
return 0;
}
///
int pd(int n,int space_c,int x,int y) //判断能否继续向下
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
if(dia[n][space_c].space[i][j]==0)
continue;
else if(face.data[x+i][y+j]==Wall || face.data[x+i][y+j]==Box)
return 0;
}
}
return 1;
}
void draw_kong(int base,int space_c,int x,int y)
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
gotoxy(x+i,2*(y+j));
if(dia[base][space_c].space[i][j]==1)
printf(" ");
}
}
}
void draw_dia(int base,int space_c,int x,int y)
{
int i,j;
for(i=0;i<4;i++)
{
for(j=0;j<4;j++)
{
gotoxy(x+i,2*(y+j));
if(dia[base][space_c].space[i][j]==1)
printf("■");
}
}
}
int color(int c)
{
switch(c)
{
case 0: c=9;break;
case 1:
case 2: c=12;break;
case 3:
case 4: c=14;break;
case 5: c=10;break;
case 6: c=13;break;
default: c=7;break;
}
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c); //更改文字颜色
return 0;
}
//
特别感谢 @丶蓝色的文章给予的启发