vs实现俄罗斯方块

1。需求分析:

背景:黑色小方块

界面:分数,等级等一般用全局变量实现

随机图形:首先用数组实现九个图形的四种状态,然后用随机数rand实现随机生成图形(常用方法)

随机图形的移动和翻转:首先要判断能不能,然后进行变动

消消乐:判断条件,下移一行

结束界面:根据自身实力设计即可

2.代码实现:

#include <graphics.h>
# include <stdio.h>
# include <time.h>
# include <conio.h>
# include <graphics.h>
enum DIR {
	UP,
	DOWN,
	LEFT,
	RIGHT
};
int a, visit[30][15], Color[30][15], minX = 30, minY = 30, maxX = 310, maxY = 610, speed = 500, score = 0, rank = 0;
int color[] = { GREEN,CYAN,MAGENTA,
				BROWN,LIGHTGRAY,LIGHTBLUE,LIGHTGREEN,
				LIGHTRED,YELLOW };
/*设计了9种方块,每种方块都有4种形态,每顺时针旋转90°就有一种形态,所以一共是36个方块。
每个方块都用5*5的二维数组来表示,
36种就是36个二维数组,所以用block[36][5][5]来表示
block[k][5][5],(k<36&&k%4==0)表示每种方块的初始形态,
k+1,+2,+3,分别表示第k种方块选择90°、180°、270°之后的形态。*/

int block[36][5][5] =
{
	{0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,1,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0},
	{0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0},
	{0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,1,0,0,0,0,0},
	{0,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,1,0,0,0,1,1,0,0},
	{0,0,0,0,0,1,0,1,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,1,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0},
	{0,1,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,1,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,1,1,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0},
	{0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0}
};
void Interface();//界面的设计
void nextblock();//生成下一个方块
void newblock();//将下一个放到主方框中
void move(int x, int y, int A);//移动方块
bool Canmove(int x0, int y0, int A, int dir, int next);//判断能否移动
bool Canrotate(int x0, int y0, int A, int next);//判断能否旋转
void mark(int x0, int y0, int A, int next);//标记方块固定后的位置
void full();//判断有没有能够消行的
void down(int x);//有消行的将上面的方块下移一行
int gameover();//判断游戏是否结束


int main() {
	Interface();
	nextblock();
	Sleep(500);
	memset(visit, 0, sizeof(visit));//初始化为全部未占有
	while (1)
	{
		newblock();
		full();
		if (gameover())
			break;
	}
	_getch();
	closegraph();
	return 0;

	
}
void Interface() {
	char str[20];
	initgraph(550, 660);
	// 获得窗口句柄
	HWND hwnd = GetHWnd();
	// 使用 Windows API 修改窗口名称
	SetWindowText(hwnd, _T("NEW俄罗斯方块                 制作:hhh"));
	Sleep(2000);
	//游戏进入界面
	setfont(40, 0, "隶体");
	setcolor(RED);
	outtextxy(145, 200, "NEW");
	setfont(40, 0, "楷体");
	for ( int i = 0; i <= 255; i++)
		for (int j = 0; j <= 255; j++)
		{
			setcolor(RGB((i + j + 128) % 255, i, j));
			outtextxy(205, 200, "俄罗斯方块!");
		}
	Sleep(2000);
	setcolor(LIGHTMAGENTA);
	Sleep(2500);
	outtextxy(130, 300,_T( "请按任意键开始游戏!"));
	if (_getch()) {
		cleardevice();
//游戏界面
		setcolor(WHITE);
		rectangle(29, 29, 334, 633);//主界面
		rectangle(28, 28, 335, 634);//主界面的框
		//下一个图形的预言界面,同时显示分数和等级
		rectangle(370, 50, 515, 195);
		setfont(24, 0, "楷体");
		setcolor(LIGHTGRAY);
		outtextxy(405, 215, "下一个:");
		setcolor(RED);
		outtextxy(405, 280, "分数:");
		sprintf_s(str, "%d", score);
		outtextxy(415, 310, str);
		outtextxy(405, 375, "等级:");
		sprintf_s(str, "%d", rank);
		outtextxy(425, 405, str);
		//操作提示
		setfont(22, 0, _T("楷体"));
		setcolor(LIGHTBLUE);
		outtextxy(390, 475, _T("操作说明:"));
		outtextxy(390, 500, _T("↑: 旋转"));
		outtextxy(390, 525, _T("↓: 下降"));
		outtextxy(390, 550, _T("←: 左移"));
		outtextxy(390, 575, _T("→: 右移"));
	}
	
}
void nextblock() {
	int x=391, y=71;
	//设置黑色背景
	setfont(23, 0, "楷体");
	setcolor(BLACK);
	for(int i=0;i<5;i++)
		for(int j=0;j<5;j++)
			outtextxy(x + j * 20, y + i * 20, "■");
	//随机的一个新图形
	 srand(time(NULL));
	 a = rand() % 8;//9种图形
	 for (int i = 0; i < 5; i++)
		 for (int j = 0; j < 5; j++)
			 if (block[4 * a][i][j])//对应该图形的第一种状态
			 {
				 setcolor(color[a]);
				 outtextxy(x + j * 20, y + i * 20, "■");
			 }
}
void newblock() {
	int x = 130, y = 30, A = a;
	//让每一次开始下降都是露出图形的最后一行
	if (A == 0 || A == 1 || A == 6)
		y -= 60;
	else if (A == 2 || A == 3 || A == 5 || A == 7 || A == 8)
		y -= 40;
	else
		y -= 80;
	setfont(23, 0, "楷体");
	setcolor(color[A]);
	for (int i = 0; i < 5; i++)
	{
		for (int j = 0; j < 5; j++)
		{
			if (block[4 * A][i][j]&&y+i*20>=30)
				outtextxy(x + j * 20, y + i * 20, "■");


		}
	}
	Sleep(100);
	nextblock();
	move(x,y,A);
}
void move(int x,int y,int A) {
	int k = 0, next = 0, Speed=speed, key, nex;
	while (1) {
		if (!Canmove(x,y+k,A,DOWN,next)) {
			mark(x, y+k, A, next);
			break;
		}
		
		//背景设置
		setcolor(BLACK);
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (block[4 * A + next][i][j] == 1 && y + 20 * i + k >= 30)
					outtextxy(x + 20 * j, y + 20 * i + k, "■");

		
		if(_kbhit())
			switch (_getch()) {
			case 'w':
			case 'W':
			//case '72':
				nex = (next + 1) % 4;
				if (Canrotate(x,y+k,A,nex))
					next = nex;
				break;
			case 's':
			case 'S':
			//case '80':
				Speed = 50;
				break;
			case 'a':
			case 'A':
			//case '75':
				if (Canmove(x, y + k + 20, A, LEFT, next))
					x -= 20;
				break;
			case 'd':
			case 'D':
			//case '77':
				if (Canmove(x, y + k + 20, A, RIGHT, next))
					x += 20;
				break;
			case '32':
				break;

		}
		setcolor(color[A]);
		for (int i = 0; i < 5; i++)
			for (int j = 0; j < 5; j++)
				if (block[4 * A + next][i][j] == 1 && y + 20 * i + k + 20 >= 30)
					outtextxy(x + 20 * j, y + 20 * i + k + 20, "■");
		Sleep(Speed);

		
		//实现每个循环下降一格
		k += 20;
	}
	
}
bool Canmove(int x0,int y0,int A,int dir,int next) {
	bool can = true;
	int x = (y0 - minY) / 20;
	int y = (x0 - minX) / 20;

	for (int i = 0; i < 5; i++) {
		for (int j = 0; j < 5; j++) {
			switch (dir) {
			case DOWN:
				if (block[4 * A + next][i][j] == 1 && (x + i + 1 == 30 || (x + i + 1 >= 0 && x + i + 1 < 30 && y + j >= 0 && y + j < 15 && visit[x + i + 1][y + j])))
					can = false; 
				break;
			case LEFT:
				if (block[4 * A + next][i][j] == 1 && (y+j == 0 || (x + i  >= 0 && x + i  < 30 && y + j -1>= 0 && y + j -1< 15 && visit[x + i ][y + j-1])))
					can = false;
				break;
			case RIGHT:
				if (block[4 * A + next][i][j] == 1 && (y+j+1==15 || (x + i  >= 0 && x + i  < 30 && y + j >= 0 && y + j -1< 15 && visit[x + i + 1][y + j+1] )))
					can = false;
				break;
			}
		}
	}
	return can;
}
bool Canrotate(int x0,int y0,int A,int next) {
	int x, y;
	x = (y0 - minY) / 20;
	y = (x0 - minX) / 20;
	bool can = true;
	if (!Canmove(x0, y0, A, DOWN, next))
		can = false;

	for (int i = 0; i < 5; i++)
		for (int j = 0; j < 5; j++)
			if (block[4 * A + next][i][j] && (y + j == -1 || y + j == 15 || (x + i >= 0 && x + i < 30 && y + j >= 0 && y + j < 15 && visit[x + i][y + j] == 1)))
				can = false;
	return can;
}

void mark(int x0,int y0,int A,int next) {
	int i, j, x, y;
	x = (y0 - minY) / 20;
	y = (x0 - minX) / 20;
	for (i = 0; i < 5; i++)
		for (j = 0; j < 5; j++)
			if (block[4 * A + next][i][j] == 1)
			{
				visit[x + i][y + j] = 1;
				Color[x + i][y + j] = color[A];
			}
}
void full() {
	int i, j,k=0;
	char str[20];
	for (i = 29; i >= 0; i--)
	{
		for (j = 0; j < 15; j++)
		{
			if (!visit[i][j])
				break;
		}
		if (j == 15) {
			k++;
			down(i);
			i++;
		}
		setcolor(RED);
		score += 10 * k;
		sprintf_s(str, "%d", score);
		outtextxy(415, 310, str);
		rank = (score / 50);
		sprintf_s(str, "%d", rank);
		outtextxy(425, 405, str);
		speed = 500 - 50 * rank;
		if (speed == 0)
			speed = 100;
		if (score >= 300)
			speed = 75;

		

	}
}void down(int x) {
	for (int i = x; i >= 0; i--) {
		for (int j = 0; j < 15; j++) {
			if (visit[i - 1][j]) {
				visit[i][j] = visit[i - 1][j];
				Color[i - 1][j] = Color[i - 1][j];
				setcolor(Color[i - 1][j]);
				outtextxy(minX + 20 * j, minY + 20 * i, "■");
			}
			else {//背景
				visit[i][j] = visit[i - 1][j];
				setcolor(BLACK);
				outtextxy(minX + 20 * j, minY + 20 * i, "■");
			}
		}//背景
		setcolor(BLACK);
		for (int j = 0; j < 15; j++)
		{
			visit[0][j] = 0;
			outtextxy(minX + 20 * j, minY, "■");
		}

	}
}
int gameover()
{
	int i, j;
	for (i = 0; i < 15; i++)
		if (visit[0][i] == 1)
		{
			for (i = 0; i <= 7; i++)
			{
				//循环式
				setcolor(RGB(35 * i, 255 - 35 * i, 255));
				for (j = i; j < 30 - i; j++, Sleep(20))
					outtextxy(30 + 20 * i, 30 + 20 * j, "■");
				for (j = i; j < 15 - i; j++, Sleep(20))
					outtextxy(30 + 20 * j, 30 + 20 * (29 - i), "■");
				for (j = 30 - 1 - i; j >= i; j--, Sleep(20))
					outtextxy(30 + 20 * (14 - i), 30 + 20 * j, "■");
				for (j = 15 - 1 - i; j >= i; j--, Sleep(20))
					outtextxy(30 + 20 * j, 30 + 20 * i, "■");
			}
			setcolor(WHITE);
			setfont(45, 0, "隶体");
			outtextxy(75, 300, "GAME OVER!");
			Sleep(5000);
			return 1;
		}
	return 0;
}

3.总结:

好习惯

1.宏定义 常量

2.enum实现DIR方向与int类型转换

注意事项:

1.vs中使用_getch(),_kbhit()

详看这篇(21条消息) 新手开始做项目问题1_hhhhhhhh_hhhhhhh的博客-CSDN博客

2.我的方向键上下左右无法实现

因此采用了wasd键

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值