俄罗斯方块(C/C++)

俄罗斯方块(C/C++)

1.设计内容
(1)设计需要生成游戏界面,包括墙壁和底
(2)然后设计生成俄罗斯方块中七个基础方块,设计旋转程序,将其进行旋转,生成21种方块模型
(3)设计程序随机生成21中模型的方块,并自动下移,设计移动方块,left,right,down移动
(4)设计判断程序,当方块碰到墙壁和底停止移动;当方块堆满一行,消除方块;当方块碰到顶,游戏结束
(5)设计隐藏光标程序,让方块在移动过程中不显示光标
2.需求分析
在本代码中,需要规定一个游戏界卖弄,包括墙壁和底部,构建出大概类似于房子的结构,需要函数来实现方块的产生,通过键盘输入来控制方块的移动(right/left/down),旋转(空格键),需要设定判断条件,当方块触碰到墙壁或者底部,便不再继续向着墙壁或者底部的方向移动,当触碰到顶部时便结束游戏,在此时,还需在设定一个判断,看用户是否要继续游戏(y/n),如果是,便继续游戏,如果否,便按任意键结束游戏,还有就是得设定一个判断,当小方块堆积满一行便进行消除。为了美观,还需要写一个子函数来对方块进行上色和隐藏光标,当然,计分又是游戏的重要一部分,我们还需要设计子函数来对玩家的分数进行记录。

3.系统设计
共设计了10个子函数来实现俄罗斯方块的生成,旋转,自由下落,实现隐藏光标,移动光标,给方块上色,制作出游戏界面,实行判断,看方块有无碰到墙壁,看方块是否堆积成一行,进行消除。记录分数,当方块碰到顶部就退出游戏,再看用户是否要继续游戏(y/n),如果是,便继续游戏,如果否,便按任意键结束游戏。
3.1 模块划分
模块分为方块的产生与清除,方块的移动与颜色,消行于计分,隐藏光标于判断方块是否到底四部分。
功能模块图
在这里插入图片描述
4编码及调试
4.1 功能一编码及调试:开始游戏
实现情况:该函数成功编译通过,实现了输出游戏界面,控制旋转次数,随即生成方块,完成了游戏规则的判断,是否还可以移动,游戏是否还继续

void stat_game()
{
	int n, ch, t = 0, x = 0, y = FACE_Y / 2 - 2, i, j;
	int space1 = 0;//旋转次数
	kongge(nn, space1, 4, FACE_Y + 3);
	n = nn;
	nn = rand() % 7;    //随机生成下一块
	color(nn);
	fangkuai(nn, space1, 4, FACE_Y + 3);
	while (1)
	{
		color(n);
		fangkuai(n, space1, x, y);//画-出图形
		if (t == 0)
			t = 15000;
		while (--t)
		{
			if (kbhit() != 0)//有输入就跳出
				break;
		}
		if (t == 0)
		{
			if (judge(n, space1, x + 1, y) == 1)
			{
				kongge(n, space1, x, y);
				x++;            //自动向下降落
			}
			else //不能下落后使图形的方为aBox
			{
				for (i = 0; i < 4; i++)
				{
					for (j = 0; j < 4; j++)
					{
						if (dia[n][space1].space[i][j] == 1)
						{
							face.data[x + i][y + j] = Box;
							face.color[x + i][y + j] = n;
							while (compare());
						}
					}
				}
				return;
			}
		}
		else
		{
			ch = getch();
			switch (ch)     //移动
			{
			case LEFT: if (judge(n, space1, x, y - 1) == 1)   //判断是否左可以移动
					   {
						   kongge(n, space1, x, y);
						   y--;
					   }
					   break;
			case RIGHT: if (judge(n, space1, x, y + 1) == 1) //判断是否右可以移动
						{
							kongge(n, space1, x, y);
							y++;
						}
						break;
			case DOWN: if (judge(n, space1, x + 1, y) == 1) //判断是否下可以移动
					   {
						   kongge(n, space1, x, y);
						   x++;
					   }
					   break;
			case SPACE: if (judge(n, (space1 + 1) % 4, x + 1, y) == 1) //判断是否能旋转
						{
							kongge(n, space1, x, y);
							space1 = (space1 + 1) % 4;
						}
						break;
			case ESC: system("cls");
				gotoxy(FACE_X / 2, FACE_Y);
				printf("---游戏结束!---\n\n");
				gotoxy(FACE_X / 2 + 2, 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;
			}
		}
	}
}

输入:空
输出:表现在方块的移动,输出“游戏结束”“按任意键退出”等字体
效果:
在这里插入图片描述
4.2 功能二编码及调试:进行消除满行
把“功能二”换成系统中的实际功能。实现情况:该函数成功编译通过,通过循环结构来实现了方块堆满一行便进行消除

int compare()
{
	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(7);
			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(2000); //延时
			system("cls");
			color(7);
			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;
}

输入:空
输出:表现在方块堆满一行便进行消除
效果:
在这里插入图片描述
4.3功能三编码及调试:判断方块是否到底
实现情况:该函数成功编译通过,通过循环结构来判断小方块是否到底,到底便不再向底部移动

int judge(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;
}

输入:空
输出:表现在方块到底便不再移动
效果:
在这里插入图片描述
4.4功能三编码及调试:输出空格
实现情况:该函数成功编译通过,成成实现了在4*4矩形中将标记为0的部位为输出为空格

void kongge(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("  ");
		}
	}

}

输入:空
输出“ “
效果:在这里插入图片描述
4.5功能三编码及调试:将方块输出
实现情况:该函数成功编译通过,成成实现了在4*4矩形中将标记为1的部位为输出为矩形

void fangkuai(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("■");
		}
	}
}

输入:空
输出;■
效果:
在这里插入图片描述
4.6功能三编码及调试:俄罗斯方块的基本形状
实现情况:该函数成功编译通过,通过来控制循环结构,在4*4的矩形下生成基本的7种俄罗斯方块,再通过循环结构来对这几种基本形状进行旋转,生成全部的21种方块

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;    //L形1

	for (i = 1; i < 4; i++)
		dia[2][0].space[i][2] = 1;
	dia[2][0].space[1][1] = 1;    //L形2

	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形?
	//基础个形状
	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个形状
}

输入:旋转(空格键)
输出:生成21种俄罗斯方块
效果:
在这里插入图片描述
4.7功能三编码及调试:设计出游戏界面和俄罗斯方块的移动
实现情况:该函数成功编译通过,通过循环来控制生成游戏界面,再判断来进行俄罗斯方块的移动

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)
			{
				face.data[i][j] = Wall;
				gotoxy(i, 2 * j);
				printf("■");
			}
			else if (i == FACE_X - 1)
			{
				face.data[i][j] = Box;
				gotoxy(i, 2 * j);
				printf("■");
			}
			else
				face.data[i][j] = Kong;
		}
	}
	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("退出 ESC");

	gotoxy(FACE_X - 8, 2 * FACE_Y + 2);
	printf("重新开始");


	gotoxy(FACE_X - 4, 2 * FACE_Y + 2);
	printf("分数%d", grade);

}

输入:<-/->
输出:表现生成的游戏界面和方块的移动上
效果:
在这里插入图片描述
在这里插入图片描述
4.8功能三编码及调试:移动光标
实现情况:该子函数成功编译通过,实现了通过光标移动来移动俄罗斯方块

void gotoxy(int x, int y) //移动光标
{
	COORD coord;
	coord.X = y;
	coord.Y = x;
	SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}

输入:空
输出:表现在方块的移动上
效果:在这里插入图片描述
4.9功能三编码及调试:隐藏光标
实现情况:该函数成功编译通过,且实现了光标的隐藏

void hidden_cursor()//隐藏光标
{
	HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
	CONSOLE_CURSOR_INFO cci;
	GetConsoleCursorInfo(hOut, &cci);
	cci.bVisible = 0;//赋1为显示,赋0为隐藏
	SetConsoleCursorInfo(hOut, &cci);
}

输入:空
输出:表现在在方块移动时不出现光标
效果:在这里插入图片描述
.10功能三编码及调试:给方块上色
实现情况:该子函数编译成功通过,实现了给方块上色的目标,符合预期设想,通过SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), c)来更改颜色

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;
}

输入:空
输出:表现在方块颜色上
效果:在这里插入图片描述
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值