俄罗斯方块 c语言实现

俄罗斯方块 c语言实现,第1张

目录

游戏说明

效果展示

 代码展示

代码解释:

存储方块

绘画界面

初始化face边框的方块信息和颜色信息

颜色

绘出方块和覆盖方块

检验方块能否移动

游戏主体

判断每行有没有被填满并消除和落下

覆盖和绘出单个方块

游戏分数

游戏结束

结束语:


游戏说明:

俄罗斯方块是大家耳熟能详的游戏,相信不用我为大家介绍了。


现在我为大家带来一些游戏的 *** 作说明:

  1. 用方向键的左右键和下键或a、s、d键还有空格键来控制方块的移动和旋转。


  2. 按r键来重新开始游戏。


  3. p键来暂停游戏,任意键继续。


效果展示:  代码展示:
#include
#include
#include
#include
#include"definition.h"
/*
编译器:vs13版          安装easyx库
安装网址:easyx.cn
*/
void format();
void color(int a);
void printbox(int a, int b, int x, int y);
void hidepastbox(int a, int b, int x, int y);
bool feasibility(int a, int b, int x, int y);
void formatinterface();
void gamebegin();
void hidebox(int i, int j);
void judgegame();
void fallbox(int i, int j,int c);
bool gameover();
int nextgame();
void updatemax();
void readmax();
void initer();
void printnumber();
void showvictory();
//声明函数
int main()
{	

	initer();
	grade = 0;   //为grade赋初始值
	readmax();
	formatinterface();
	format();
	gamebegin();
	return 0;
}
void initer()     //将face.date和face.color数组数据初始化为0和9
{
	for (int i = 0; i < width + 10; i++)
	{
		for (int j = 0; j < hight; j++)
		{
			face.date[i][j] = 0;
			face.color[i][j] = 9;
		}
	}
}
void formatinterface()    //将界面初始化
{
	initgraph(check*(width+ 10), hight*check);     //创建一个有30*30方块点的画布
	setbkcolor(WHITE);                             //将画布背景设为白色
	cleardevice();                                //在setbkcolor函数后要用cleardevice刷新画布
	for (int i = 0; i < width + 10; i++)
	{
		for (int j = 0; j < hight; j++)
		{
			setlinecolor(LIGHTGRAY);
			line(i*check, 0, i*check, 450);
			line(0, j*check, 450, j*check);
			if (i == 0 || i == width || i == width + 9)
			{
				setfillcolor(DARKGRAY);          
				fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check);  //这个循环用来画出纵向排列的方格
				face.date[i][j] = 1;  //记录界面信息
				face.color[i][j] = 7;  //记录界面颜色信息,作者这里认为可以不用。






} else if (j = hight - 1) { color(7); fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); //这个循环用来画出横向排列的方格 face.date[i][j] = 1; face.color[i][j] = 7; } } for (int i = 20; i < 30; i++) { int j = 8; color(7); fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); //这个循环来画出方块预览区的分界线 } settextcolor(BLACK); //字的颜色 setbkmode(TRANSPARENT);//字的背景为透明 settextstyle(check, 0,_T("Consolas")); //字的大小跟字体 outtextxy(21 * check, 9 * check,_T("当前得分:")); outtextxy(21 * check, 12 * check, _T("用方向键,ASD键或")); outtextxy(21 * check, 13 * check, _T("方向键控制方块")); outtextxy(21 * check, 14 * check, _T("移动")); outtextxy(21 * check, 18 * check, _T("按r键重新开始")); outtextxy(21 * check, 19 * check, _T("按p键暂停游戏")); //在提示去打印文字提示,作者这里outtextxy函数用的不熟练,应该有更好的方法 } } void color(int a) //创建一个颜色函数用数字来存储每个方块的颜色信息 { switch (a) { case 0: { setfillcolor(RED); //红色RED break; } case 1: { setfillcolor(BROWN); //棕色BROWN break; } case 2: { setfillcolor(BLUE); //蓝色BULE break; } case 3: { setfillcolor(GREEN); //绿色GREEN break; } case 4: { setfillcolor(YELLOW); //黄色YELLOW break; } case 5: { setfillcolor(MAGENTA); //紫色MAGENTA break; } case 6: { setfillcolor(CYAN); //青色CYAN break; } case 7: { setfillcolor(DARKGRAY); //深灰色DARKGRAY break; } case 8: { setfillcolor(WHITE); //白色WHITE break; } } } void format() //将7*4种方块信息存储到box结构体数组里面 { for (int i = 0; i < 4; i++) { box[0][0].space[i][1] = 1; } //I型; for (int i = 0; i < 3; i++) { box[1][0].space[i][1] = 1; } box[1][0].space[1][2] = 1; //上型; for (int i = 1; i < 3; i++) { box[2][0].space[1][i] = 1; box[2][0].space[2][i] = 1; // 田型; box[3][0].space[1][i] = 1; box[3][0].space[i][0] = 1; //L型; } for (int i = 1; i < 3; i++) { box[4][0].space[1][i] = 1; box[4][0].space[2][i + 1] = 1; //Z型; box[5][0].space[2][i] = 1; box[5][0].space[i][0] = 1; //倒L型; } for (int i = 1; i < 3; i++) { box[6][0].space[1][i] = 1; box[6][0].space[2][i - 1] = 1; } int temp[4][4]; for (int i = 0; i<7; i++) { for (int j = 0; j<3; j++) { for (int a = 0; a<4; a++) { for (int b = 0; b<4; b++) { temp[a][b] = box[i][j].space[a][b]; //这个循环来存储上面方块旋转后的形态 } } for (int a = 0; a<4; a++) { for (int b = 0; b<4; b++) { box[i][j + 1].space[a][b] = temp[3 - b][a]; } } } } } void printbox(int a, int b, int x, int y) //绘出方块 { color(a); //设置颜色调用上面定义的void color(int)函数 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (box[a][b].space[i][j] == 1) //检验该位置有没有方块 { fillrectangle((i + x)*check, (j + y)*check, (i + 1 + x)*check, (j + 1 + y)*check); } } } } void hidepastbox(int a, int b, int x, int y) //覆盖方块的函数 { color(8); //将颜色设置为与背景一样的白色达到覆盖的效果 for (int i = 0; i < 4; i++) //之后的代码和上面绘出方块的函数一毛一样 { for (int j = 0; j < 4; j++) { if (box[a][b].space[i][j] == 1) { fillrectangle((i + x)*check, (j + y)*check, (i + 1 + x)*check, (j + 1 + y)*check); } } } } bool feasibility(int a, int b, int x, int y) //定义一个波尔型函数来判断方块的移动是否可行 { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (box[a][b].space[i][j] == 1 && face.date[x + i][y + j] == 1) //检验方块与界面是否重合 return false; //若重合则返回假 } } return true; //若不重合则返回真 } void gamebegin() //此游戏代码中作者认为最重要的函数 { srand((unsigned)time(NULL)); //防止生成伪随机数 int a = rand() % 7, b = rand() % 4; //随机生成输出方块的形状和形式 while (1) { int whereabouts = 0; //定义一个工具数,除了检验键盘有没有按键外,毫无卵用 int a1 = rand() % 7, b1 = rand() % 4; //随机生成下一个方块的形状和形式 int x = 9, y = 0; //定义方块刚开始落下的坐标 printbox(a1, b1, 23, 3); //在提前做好的预览区画出下一个方块 while (1) { printbox(a, b, x, y); //在(x,y)处画出方块 每循环一次都要画一次,配合下面的覆盖方块函数就有了一个动画的效果 if (whereabouts == 0) { whereabouts = 10000; //给whereabouts赋个值,whereabouts越小方块下落的越快,看了下面的就明白了 } while (--whereabouts) { if (kbhit() != 0) /*kbhit()是一个检验键盘有没有按下的int型函数,若键盘有被按下,则会返回一个非零值,反之返回0 这个if就是用来检验键盘有没有被按下,如果键盘又被按下whereabouts就会停止自减,实现下面使方块移动的代码 */ break; } if (whereabouts == 0) { //如果键盘没有被按下,whereabouts自减成零 if (feasibility(a, b, x, y + 1)) //先判断方块落下是否跟边框或其他方块重合 { hidepastbox(a, b, x, y); //如果不重合,就把之前的方块覆盖再让y自加1 y++; } else { //如果重合的话,说明方块底部已经碰到其他方块或边框 for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { if (box[a][b].space[i][j] == 1) { face.date[i + x][j + y] = 1; //将以落地方块所在的位置信息在face.date上存储 face.color[i + x][j + y] = a; //同理,存储颜色信息 } } } judgegame(); //判断函数,方块每落一次地都要判断每行是否已满,这个函数详情函数定义的时候有注释 if (gameover()) //同理函数每落一次地都要判断游戏是否已结束,定义的时候也有注释 { if (grade > max) //如果得分超过之前记录 { updatemax(); //更新文件里的最高分 } int n = nextgame(); //用n来存储nextgame函数的返回值 switch (n) { case 1: { closegraph(); //若函数返回值为1,关闭画布,退出程序。


exit(0); break; } case 2: { main(); //返回值为2,则意味要进行下一把游戏,返回main()函数重新进行一把游戏 break; } } } else { break; } } } else //如果键盘有被按下 { switch (getch()) //获取键盘信息 { case 'a': case 'A': //aA方向键左键都说明要向左移动方块 case 75: { if (feasibility(a, b, x - 1, y)) //判断移动是否可行 { hidepastbox(a, b, x, y); //覆盖方块,再让x自减1,下面基本同理,不做过多解释 x--; } break; } case 32: //这是空格键的ASCII值 { if (feasibility(a, (b + 1) % 4, x, y + 1)) //为了让b加一后其数值不超过4,(b+1)%4 { hidepastbox(a, b, x, y); b = (b + 1) % 4; y++; } break; } case 's': case 'S': case 80: { if (feasibility(a, b, x, y + 1)) { hidepastbox(a, b, x, y); y++; } break; } case 'd': case 'D': case 77: { if (feasibility(a, b, x + 1, y)) { hidepastbox(a, b, x, y); x++; } break; } case 'r': case 'R': //若玩家按下r/R键,返回主函数,重新开始游戏 { main(); break; } case 'p': //若玩家按下p键,暂停游戏,按下任意键继续游戏 { system("pause"); break; } } } } a = a1; b = b1; x = 9; y = 0; hidepastbox(a1, b1, 23, 3); } } void judgegame() //判断每行是否被填满的函数 { for (int i = 28; i >= 1; i--) { int n = 0; //用n来记录每行有几个方块 for (int j = 1; j < 19; j++) { n = n + face.date[j][i]; } if (n == 18) //如果第i行满了的话 { grade = grade + 10; //分数+10 printnumber(); //更新画布的分数函数 for (int j = 1; j<19; j++) { face.date[j][i] = 0; hidebox(i, j); //将第i行的方块覆盖掉 } for (int m = i; m>1; m--) { for (int j = 1; j < 19; j++) { face.date[j][m] = face.date[j][m - 1]; face.color[j][m] = face.color[j][m - 1]; //将上一行的数据传递给下一行,来实现下面在第i行画出i-1行方块的代码 if (face.date[j][m] == 1) { fallbox(j, m,face.color[j][m]); //画方块的函数,与printbox函数不同的是,这个函数一个一个的画 } else if (face.date[j][m] == 0) { hidebox(j, m); //一个一个覆盖方块的函数 } } } } else if (n == 0) //如果这行没有一个方块,则说明上面也没有方块,则不需要继续进行循环,推出循环 { break; } } } void printnumber() { hidebox(27, 9); hidebox(28, 9); //覆盖原来的分数 _stprintf(s, _T("%d"), grade); //将grade转变为字符型 settextcolor(BLACK); //设置字的颜色 setbkmode(TRANSPARENT); settextstyle(check, 0, _T("Consolas")); outtextxy(27 * check, 9 * check, s); //在指定位置输出分数 } void hidebox(int i, int j) { color(8); //用白色,达到覆盖的效果 fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); } void fallbox(int i, int j, int c) { color(c); //用已经存储的颜色达到与消除方块前上一行方块颜色相同的效果 fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); } int nextgame() { int i; //用i来存储MessageBox的返回值 i = MessageBox(NULL, L"是否重新开一把?", L"俄罗斯方块", MB_OKCANCEL); if (i == IDOK) { return 2; } else { return 1; } } bool gameover() { for (int i = 1; i < 19; i++) { if (face.date[i][1] == 1) //若第一行有方块,则说明游戏结束 { return true; } } return false; } void updatemax() { showvictory(); //定义有注释 FILE * pf; pf = fopen("俄罗斯方块最高分.txt", "w"); //以只写的方式打开文本文档 if (pf == NULL) { printf("保存最高纪录失败"); exit(0); } fwrite(&grade, sizeof(int), 1, pf); //将grade存储到文本文档 fclose(pf); //关闭文件 } void showvictory() { setbkcolor(WHITE); clearcliprgn(); //刷新画布,清空画布 settextcolor(RED); settextstyle(2 * check, 0, _T("Consolas")); outtextxy(15 * check, 15 * check, _T("恭喜超过最高记录")); //在画布中央输出恭喜信息 } void readmax() { FILE* pf; begin: pf = fopen("俄罗斯方块最高分.txt", "r"); if (pf == NULL) { pf = fopen("俄罗斯方块最高分.txt", "w"); //如果打开文件失败,就重新创建一个 goto begin; } fread(&max, sizeof(int), 1, pf); //在文件中读取max fclose(pf); }

#define width 20  //这是方块移动的边框宽度
#define hight 30  //这是边框的高度
#define check 15   //这是每个方块的边长,以像素为单位的
struct INTERFACE
{
	int date[width + 10][hight];    //方块信息
	int color[width + 10][hight];  //颜色信息
}face;
struct BOX
{
	int space[4][4];    //方块信息,因为方块最长的为4,所以定义为4*4的
}box[7][4];          //7个形状,4个形态
int max;    //最高分
int grade;   //分数
TCHAR s[100];   //分数在画布输出时要转化为字符型,这是存储分数的字符型变量,其实作者也不知道这是个啥。










代码解释: 存储方块:

把方块存储起来,输出方块的时候拿出来用现成的数据

void format()   //将7*4种方块信息存储到box结构体数组里面
{
	for (int i = 0; i < 4; i++)
	{
		box[0][0].space[i][1] = 1;
	}   //I型;
	for (int i = 0; i < 3; i++)
	{
		box[1][0].space[i][1] = 1;
	}
	box[1][0].space[1][2] = 1;  //上型;
	for (int i = 1; i < 3; i++)
	{
		box[2][0].space[1][i] = 1;
		box[2][0].space[2][i] = 1; // 田型;
		box[3][0].space[1][i] = 1;
		box[3][0].space[i][0] = 1; //L型;

	}
	for (int i = 1; i < 3; i++)
	{
		box[4][0].space[1][i] = 1;
		box[4][0].space[2][i + 1] = 1;  //Z型;
		box[5][0].space[2][i] = 1;
		box[5][0].space[i][0] = 1;  //倒L型;
	}
	for (int i = 1; i < 3; i++)
	{
		box[6][0].space[1][i] = 1;
		box[6][0].space[2][i - 1] = 1;
	}
	int temp[4][4];
	for (int i = 0; i<7; i++)
	{
		for (int j = 0; j<3; j++)
		{
			for (int a = 0; a<4; a++)
			{
				for (int b = 0; b<4; b++)
				{
					temp[a][b] = box[i][j].space[a][b];   //这个循环来存储上面方块旋转后的形态
				}
			}
			for (int a = 0; a<4; a++)
			{
				for (int b = 0; b<4; b++)
				{
					box[i][j + 1].space[a][b] = temp[3 - b][a];
				}
			}
		}
	}
}
绘画界面:

绘出一个30*30个方块的界面,20*30的地方来进行游戏,10*30的地方作为预览区和提示区

void formatinterface()    //将界面初始化
{
	initgraph(check*(width+ 10), hight*check);     //创建一个有30*30方块点的画布
	setbkcolor(WHITE);                             //将画布背景设为白色
	cleardevice();                                //在setbkcolor函数后要用cleardevice刷新画布
	for (int i = 0; i < width + 10; i++)
	{
		for (int j = 0; j < hight; j++)
		{
			setlinecolor(LIGHTGRAY);
			line(i*check, 0, i*check, 450);
			line(0, j*check, 450, j*check);
			if (i == 0 || i == width || i == width + 9)
			{
				setfillcolor(DARKGRAY);          
				fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check);  //这个循环用来画出纵向排列的方格
				face.date[i][j] = 1;  //记录界面信息
				face.color[i][j] = 7;  //记录界面颜色信息,作者这里认为可以不用。






} else if (j = hight - 1) { color(7); fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); //这个循环用来画出横向排列的方格 face.date[i][j] = 1; face.color[i][j] = 7; } } for (int i = 20; i < 30; i++) { int j = 8; color(7); fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check); //这个循环来画出方块预览区的分界线 } settextcolor(BLACK); //字的颜色 setbkmode(TRANSPARENT);//字的背景为透明 settextstyle(check, 0,_T("Consolas")); //字的大小跟字体 outtextxy(21 * check, 9 * check,_T("当前得分:")); outtextxy(21 * check, 12 * check, _T("用方向键,ASD键或")); outtextxy(21 * check, 13 * check, _T("方向键控制方块")); outtextxy(21 * check, 14 * check, _T("移动")); outtextxy(21 * check, 18 * check, _T("按r键重新开始")); outtextxy(21 * check, 19 * check, _T("按p键暂停游戏")); //在提示去打印文字提示,作者这里outtextxy函数用的不熟练,应该有更好的方法 } }

初始化face边框的方块信息和颜色信息:

这个函数存在主要是如果在游戏中或游戏结束后进行下一场游戏的话,数组的元素已经改变,会有bug,所以把这个函数放到主函数里,来消除bug。


void initer()     //将face.date和face.color数组数据初始化为0和9
{
	for (int i = 0; i < width + 10; i++)
	{
		for (int j = 0; j < hight; j++)
		{
			face.date[i][j] = 0;
			face.color[i][j] = 9;
		}
	}
}
颜色:

这里也要说一下这个函数的作用,如果想要将方块变得五颜六色,就要存储每个方块的颜色信息,不然在消除方块后,落下方块会有bug,如果阉割颜色的画,这个函数也不是必要的。


void color(int a)      //创建一个颜色函数用数字来存储每个方块的颜色信息
{
	switch (a)
	{
	case 0:
	{
			  setfillcolor(RED);         //红色RED
			  break;
	}
	case 1:
	{
			  setfillcolor(BROWN);     //棕色BROWN
			  break;
	}
	case 2:
	{
			  setfillcolor(BLUE);          //蓝色BULE
			  break;
	}
	case 3:
	{
			  setfillcolor(GREEN);         //绿色GREEN
			  break;
	}
	case 4:
	{
			  setfillcolor(YELLOW);      //黄色YELLOW
			  break; 
	}
	case 5:
	{
			  setfillcolor(MAGENTA);     //紫色MAGENTA
			  break;
	}
	case 6:
	{
			  setfillcolor(CYAN);     //青色CYAN
			  break;
	}
	case 7:
	{
			  setfillcolor(DARKGRAY);  //深灰色DARKGRAY
			  break;
	}
	case 8:
	{
			  setfillcolor(WHITE);  //白色WHITE
			  break;
	}
	}
}
绘出方块和覆盖方块:
void printbox(int a, int b, int x, int y)   //绘出方块
{
	color(a);                              //设置颜色调用上面定义的void color(int)函数
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (box[a][b].space[i][j] == 1)   //检验该位置有没有方块
			{
				fillrectangle((i + x)*check, (j + y)*check, (i + 1 + x)*check, (j + 1 + y)*check);
			}
		}
	}
}
void hidepastbox(int a, int b, int x, int y)  //覆盖方块的函数
{
	color(8);     //将颜色设置为与背景一样的白色达到覆盖的效果
	for (int i = 0; i < 4; i++)   //之后的代码和上面绘出方块的函数一毛一样
	{
		for (int j = 0; j < 4; j++)
		{
			if (box[a][b].space[i][j] == 1)
			{
				fillrectangle((i + x)*check, (j + y)*check, (i + 1 + x)*check, (j + 1 + y)*check);
			}
		}
	}
}
检验方块能否移动:

将此函数定义为bool型,bool型只有俩个值,true(真)false(假)。


bool feasibility(int a, int b, int x, int y)   //定义一个波尔型函数来判断方块的移动是否可行
{
	for (int i = 0; i < 4; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (box[a][b].space[i][j] == 1 && face.date[x + i][y + j] == 1)  //检验方块与界面是否重合
				return false;                                       //若重合则返回假
		}
	}
	return true;               //若不重合则返回真
}
游戏主体:
void gamebegin()          //此游戏代码中作者认为最重要的函数
{
		srand((unsigned)time(NULL));  //防止生成伪随机数
		int a = rand() % 7, b = rand() % 4;   //随机生成输出方块的形状和形式
		while (1)
		{
			int whereabouts = 0;     //定义一个工具数,除了检验键盘有没有按键外,毫无卵用
			int a1 = rand() % 7, b1 = rand() % 4;   //随机生成下一个方块的形状和形式
			int x = 9, y = 0;     //定义方块刚开始落下的坐标
			printbox(a1, b1, 23, 3);    //在提前做好的预览区画出下一个方块
			while (1)                   
			{
				printbox(a, b, x, y);  //在(x,y)处画出方块 每循环一次都要画一次,配合下面的覆盖方块函数就有了一个动画的效果
				if (whereabouts == 0)
				{
					whereabouts = 10000;     //给whereabouts赋个值,whereabouts越小方块下落的越快,看了下面的就明白了
				}
				while (--whereabouts)     
				{
					if (kbhit() != 0)    /*kbhit()是一个检验键盘有没有按下的int型函数,若键盘有被按下,则会返回一个非零值,反之返回0
										 这个if就是用来检验键盘有没有被按下,如果键盘又被按下whereabouts就会停止自减,实现下面使方块移动的代码
										 */
						break;
				}
				if (whereabouts == 0)    
				{                                            //如果键盘没有被按下,whereabouts自减成零
					if (feasibility(a, b, x, y + 1))         //先判断方块落下是否跟边框或其他方块重合
					{
						hidepastbox(a, b, x, y);                //如果不重合,就把之前的方块覆盖再让y自加1
						y++;
					}
					else
					{                                        //如果重合的话,说明方块底部已经碰到其他方块或边框
						for (int i = 0; i < 4; i++)
						{
							for (int j = 0; j < 4; j++)
							{
								if (box[a][b].space[i][j] == 1)
								{
									face.date[i + x][j + y] = 1;           //将以落地方块所在的位置信息在face.date上存储
									face.color[i + x][j + y] = a;            //同理,存储颜色信息
								}
							}
						}
						judgegame();         //判断函数,方块每落一次地都要判断每行是否已满,这个函数详情函数定义的时候有注释
						if (gameover())     //同理函数每落一次地都要判断游戏是否已结束,定义的时候也有注释
						{
							if (grade > max)   //如果得分超过之前记录
							{
								updatemax();   //更新文件里的最高分
							}
							int n = nextgame();  //用n来存储nextgame函数的返回值
							switch (n)
							{
							case 1:
							{
									  closegraph();    //若函数返回值为1,关闭画布,退出程序。


exit(0); break; } case 2: { main(); //返回值为2,则意味要进行下一把游戏,返回main()函数重新进行一把游戏 break; } } } else { break; } } } else //如果键盘有被按下 { switch (getch()) //获取键盘信息 { case 'a': case 'A': //aA方向键左键都说明要向左移动方块 case 75: { if (feasibility(a, b, x - 1, y)) //判断移动是否可行 { hidepastbox(a, b, x, y); //覆盖方块,再让x自减1,下面基本同理,不做过多解释 x--; } break; } case 32: //这是空格键的ASCII值 { if (feasibility(a, (b + 1) % 4, x, y + 1)) //为了让b加一后其数值不超过4,(b+1)%4 { hidepastbox(a, b, x, y); b = (b + 1) % 4; y++; } break; } case 's': case 'S': case 80: { if (feasibility(a, b, x, y + 1)) { hidepastbox(a, b, x, y); y++; } break; } case 'd': case 'D': case 77: { if (feasibility(a, b, x + 1, y)) { hidepastbox(a, b, x, y); x++; } break; } case 'r': case 'R': //若玩家按下r/R键,返回主函数,重新开始游戏 { main(); break; } case 'p': //若玩家按下p键,暂停游戏,按下任意键继续游戏 { system("pause"); break; } } } } a = a1; b = b1; x = 9; y = 0; hidepastbox(a1, b1, 23, 3); } }

判断每行有没有被填满并消除和落下:
void judgegame()   //判断每行是否被填满的函数
{
	for (int i = 28; i >= 1; i--)
	{
		int n = 0;         //用n来记录每行有几个方块
		for (int j = 1; j < 19; j++)
		{
			n = n + face.date[j][i];
		}
		if (n == 18)     //如果第i行满了的话
		{
			grade = grade + 10;  //分数+10
			printnumber();        //更新画布的分数函数
			for (int j = 1; j<19; j++)
			{
				face.date[j][i] = 0;
				hidebox(i, j);             //将第i行的方块覆盖掉
			}
			for (int m = i; m>1; m--)
			{
				for (int j = 1; j < 19; j++)
				{
					face.date[j][m] = face.date[j][m - 1];
					face.color[j][m] = face.color[j][m - 1];           //将上一行的数据传递给下一行,来实现下面在第i行画出i-1行方块的代码
					if (face.date[j][m] == 1)
					{
						fallbox(j, m,face.color[j][m]);              //画方块的函数,与printbox函数不同的是,这个函数一个一个的画
					}
					else if (face.date[j][m] == 0)
					{
						hidebox(j, m);                     //一个一个覆盖方块的函数
					}
				}
			}
		}
		else if (n == 0)             //如果这行没有一个方块,则说明上面也没有方块,则不需要继续进行循环,推出循环
		{
			break;
		}
	}
}
覆盖和绘出单个方块:

此函数在检测出每行有方块被填满后用的函数

void hidebox(int i, int j)
{
	color(8); //用白色,达到覆盖的效果
	fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check);
}
void fallbox(int i, int j, int c)
{
	color(c);   //用已经存储的颜色达到与消除方块前上一行方块颜色相同的效果
	fillrectangle(i*check, j*check, (i + 1)*check, (j + 1)*check);
}
游戏分数:
void printnumber()
{
	hidebox(27, 9);
	hidebox(28, 9);              //覆盖原来的分数
	_stprintf(s, _T("%d"), grade);       //将grade转变为字符型
	settextcolor(BLACK);               //设置字的颜色
	setbkmode(TRANSPARENT);
	settextstyle(check, 0, _T("Consolas"));
	outtextxy(27 * check, 9 * check, s);             //在指定位置输出分数
}
void readmax()
{
	FILE* pf;
	begin:
		pf = fopen("俄罗斯方块最高分.txt", "r");
	if (pf == NULL)
	{
		pf = fopen("俄罗斯方块最高分.txt", "w");   //如果打开文件失败,就重新创建一个
		goto begin;
	}
	fread(&max, sizeof(int), 1, pf);     //在文件中读取max
	fclose(pf);
}
void updatemax()
{
	showvictory();    //定义有注释
	FILE * pf;
	pf = fopen("俄罗斯方块最高分.txt", "w");  //以只写的方式打开文本文档
	if (pf == NULL)
	{
		printf("保存最高纪录失败");
		exit(0);
	}
	fwrite(&grade, sizeof(int), 1, pf);  //将grade存储到文本文档
	fclose(pf);           //关闭文件
}
游戏结束:
int nextgame()
{
			int i;     //用i来存储MessageBox的返回值
			i = MessageBox(NULL, L"是否重新开一把?", L"俄罗斯方块", MB_OKCANCEL);
			if (i == IDOK)
			{
				return 2;    
			}
			else
			{
				return 1;
				
			}
			
		
}
bool gameover()
{
	for (int i = 1; i < 19; i++)
	{
		if (face.date[i][1] == 1)        //若第一行有方块,则说明游戏结束
		{
			return true;
		}
	}
	return false;
}
void showvictory()
{
	setbkcolor(WHITE);    
	clearcliprgn();  //刷新画布,清空画布
	settextcolor(RED);
	settextstyle(2 * check, 0, _T("Consolas"));
	outtextxy(15 * check, 15 * check, _T("恭喜超过最高记录"));  //在画布中央输出恭喜信息
}
结束语:

本人为大一生,爱好c语言和其他编译语言,如果对此代码有建议,希望能在评论区点评

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/584815.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存