详解51单片机点阵屏如何实现俄罗斯方块游戏

文章目录

前言

一、关于点阵屏

二、俄罗斯方块代码部分

1.main主函数

2.按键扫描

3.方块生成

4.方块显示 

5.方块下降 

 6.固定的方块显示

7.方块的左右移动

8.键值的判断与执行 

9.方块的旋转 

 10.总代码

总结


前言

这里采用的是清翔51单片机,通过独立键盘实现左右移动和旋转,通过8×8点阵屏显示


一、关于点阵屏

 

 行选值默认是低电平0,列选值默认是高电平1,通过74HC595芯片可以将数据进行串入并出输入然后就可以显示了。

二、俄罗斯方块代码部分

1.main主函数

从主函数开始看会清晰很多。

void main()
{
	uchar j, k, i;
	for (j = 0; j < 8; j++)
		for (k = 0; k < 9; k++)
			axis[j][k] = 1;//8×8点阵屏上面的每一个点都初始化为1(1代表点亮,0代表熄灭),这样便于后面显示
	timer0Init();//定时器0初始化
	while (1)
	{
		scan();//判断键值,并通过键值执行相应指令
		if (a)
		{
			Random();//生成一个随机图形(仅生成一次)
			a = 0;
		}
		if (m == 40)
		{
			down();//定时器没定时一次m++,m到40的时候图形下降一格
			m = 0;
		}
		Clear();//判断有没有一行全部点亮,有就消除
		for (i = 0; i < 8; i++)
		{
			if (axis[i][8] == 0)//判断游戏结束
				return;
		}
	}
}

首先定义了一个二维数组用来存放点阵屏64个点的状态,通过0,1的方式存储,这样存储的好处是在显示图像的时候可以通过运算把每一行的值给算出来并通过74HC595这个芯片传给点阵屏。这个二维数组设置为[8][9]是因为最上面要有一行用来判断游戏是否结束的,最上面一行一旦出现0,那么游戏结束 。

uchar axis[8][9] = { 0 };

 通过下面这种方式算出其行值

axis[0][i] * 128 + axis[1][i] * 64 + axis[2][i] * 32 + axis[3][i] * 16 + axis[4][i] * 8 + axis[5][i] * 4 + axis[6][i] * 2 + axis[7][i] * 1

 接下来是定时器中断的配置以及内容

void timer0Init()
{
	EA = 1;
	ET0 = 1;
	TR0 = 1;
	TMOD = 0X01;
	TH0 = 0XDD;
	TL0 = 0XFF;
}
void timer0() interrupt 1
{
	TH0 = 0XDD;
	TL0 = 0XFF;
	m++;
	KeyScan();//按键扫描
	for (d = 0; d < 4; d++)
	{
		if (yy[d] <= 8 && yy[d] >= 1)
			displaymove(coorx[xx[d] - 1], coory[yy[d] - 1]);//对于活动的图形的显示
	}
	displayfixed();//对于已经固定的图形显示
}

 这里也可以看出来我把显示图像分成了两部分

2.按键扫描

要想实现方块的左右移动以及图形旋转就要用到键盘,所以这里先展示键盘部分代码,键盘为了保证单片机能立刻反应,最好放在定时器中断里面,我只用到了3个按键,第一个是左移,第二个是顺时针旋转,第四个是右移,第三个按键可以自己设计,比如加速下落,逆时针旋转之类的。

void KeyScan()
{
	if (key_s2 == 0)
	{
		delay(10);
		if (key_s2 == 0)
		{
			key = 1;
		}
	}
	if (key_s3 == 0)
	{
		delay(10);
		if (key_s3 == 0)
		{
			key = 2;
		}
	}
	if (key_s4 == 0)//这一个按键其实没用到
	{
		delay(10);
		if (key_s4 == 0)
		{
			key = 3;
		}
	}
	if (key_s5 == 0)
	{
		delay(10);
		if (key_s5 == 0)
		{
			key = 4;
		}
	}
}

3.方块生成

方块生成就要用到随机函数了由于每个方块都是由4个小方块组成的,所以我这里又定义了2个数组分别代表每个方块的坐标,关于坐标, x轴是1到8,y轴是1到12,因为生成的图形要慢慢显示出来所以在最上方留了4行,所以下面坐标会出现9到12。我的代码比较繁琐,我把每一种情况都列了出来,没想到什么更好的方法。.

uchar xx[4];
uchar yy[4];
void Random()
{
	ran = rand() % 19 + 1;
	switch (ran)
	{
	case 1:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 2:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 6; yy[3] = 10; break;
	case 3:xx[0] = 5; yy[0] = 9; xx[1] = 5; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 5; yy[3] = 11; break;
	case 4:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 5; yy[2] = 9; xx[3] = 5; yy[3] = 10; break;
	case 5:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 6:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 6; yy[2] = 9; xx[3] = 4; yy[3] = 10; break;
	case 7:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 5; yy[3] = 11; break;
	case 8:xx[0] = 5; yy[0] = 9; xx[1] = 3; yy[1] = 10; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 9:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 6; yy[2] = 9; xx[3] = 5; yy[3] = 10; break;
	case 10:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 11:xx[0] = 4; yy[0] = 9; xx[1] = 3; yy[1] = 10; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 12:xx[0] = 5; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 13:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 3; yy[2] = 10; xx[3] = 4; yy[3] = 10; break;
	case 14:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 15:xx[0] = 5; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 16:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 17:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 5; yy[2] = 9; xx[3] = 6; yy[3] = 9; break;
	case 18:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 4; yy[3] = 12; break;
	case 19:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	}
}

然后我把每一个ran值对应的图形给出来

1.
0 0 0 0
0 2 0 0
0 2 0 0
0 2 2 0

2.
0 0 0 0
0 0 0 0
0 2 2 2
0 2 0 0

3.
0 0 0 0
0 2 2 0
0 0 2 0
0 0 2 0

4.
0 0 0 0
0 0 0 0
0 0 2 0
2 2 2 0

5.
0 0 0 0
0 0 2 0
0 0 2 0
0 2 2 0

6.
0 0 0 0
0 0 0 0
0 2 0 0
0 2 2 2

7.
0 0 0 0
0 2 2 0
0 2 0 0
0 2 0 0

8.
0 0 0 0
0 0 0 0
2 2 2 0
0 0 2 0

9.
0 0 0 0
0 0 0 0
0 0 2 0
0 2 2 2

10.
0 0 0 0 
0 2 0 0
0 2 2 0
0 2 0 0

11.
0 0 0 0
0 0 0 0
2 2 2 0
0 2 0 0

12.
0 0 0 0
0 0 2 0
0 2 2 0
0 0 2 0

13.
0 0 0 0
0 0 0 0
2 2 0 0
0 2 2 0

14.
0 0 0 0
0 0 2 0
0 2 2 0
0 2 0 0

15.
0 0 0 0
0 2 0 0
0 2 2 0
0 0 2 0

16.
0 0 0 0
0 0 0 0
0 2 2 0
2 2 0 0

17.
0 0 0 0
0 0 0 0
0 0 0 0
2 2 2 2

18.
0 2 0 0
0 2 0 0
0 2 0 0
0 2 0 0

19.
0 0 0 0
0 0 0 0
0 2 2 0
0 2 2 0

4.方块显示 

方块既然生成了,总得让他显示吧,而这个显示是实时的所以放在中断里面,而这个方块坐标的数据是不能传给点阵屏的,所以需要将坐标转化,于是就引入了这两个数组。举个例子,坐标是(1,1)那么就把coorx[1-1],coory[1-1]传进去这样(1, 1)这个点就能显示了。同样的道理,对四个点进行扫描,就可以显示出方块了

uchar coorx[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
uchar coory[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
void SendByte(uchar dat)
{
	uchar i;
	S_CLK = 0;
	R_CLK = 0;
	for (i = 0; i < 8; i++)
	{
		if (dat & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;
		S_CLK = 0;
		dat >>= 1;
	}
}

void displaymove(uchar dat1, uchar dat2)
{
	SendByte(dat1);
	SendByte(dat2);
	R_CLK = 1;
	R_CLK = 0;
}

 这里if说一下,由于坐标设置的是9到12行的地方,超出了点阵屏的范围,所以要设置一个范围约束一下,等到下降的时候就可以显示了。

for (d = 0; d < 4; d++)
	{
		if (yy[d] <= 8 && yy[d] >= 1)
			displaymove(coorx[xx[d] - 1], coory[yy[d] - 1]);//对于活动的图形的显示
	}

5.方块下降 

这一步挺麻烦的,要考虑很多东西,这里补充一下,对于方块的生成,我对每一个小方块是按次序编号的,按从左往右,从下往上的次序,所以这里判定是否到达下边界的代码中我直接使用了if (yy[0] <= 1)yy[0]肯定是最下面的那个方块,如果最下面那个碰到下边界就停止了。

void down()
{
	uchar n;
	if (yy[0] <= 1)
	{
		for (n = 0; n < 4; n++)
		{
			axis[xx[n] - 1][yy[n] - 1] = 0;//碰到边界了,此时这四个点的状态置为0,之后会将这个方块显示出来
		}
		Random();//方块停止了,需要重新生成方块
	}
	else
	{
		if (yy[0] <= 9 && yy[1] <= 9 && yy[2] <= 9 && yy[3] <= 9)//约束范围,防止越界
		{
			if (axis[xx[0] - 1][yy[0] - 2] == 1 && axis[xx[1] - 1][yy[1] - 2] == 1 && axis[xx[2] - 1][yy[2] - 2] == 1 && axis[xx[3] - 1][yy[3] - 2] == 1)//判断下一个方块下移过程中是否碰到了已经被固定了的方块,如果碰到就不下降了
			{
				for (n = 0; n < 4; n++)
				{
					yy[n]--;
				}
			}
			else
			{
				for (n = 0; n < 4; n++)
				{
					axis[xx[n] - 1][yy[n] - 1] = 0;//如果方块被固定了,那么这个方块所在的位置的状态就会被赋给axis,便于后续的显示
				}
				Random();
			}
		}
		else
		{
			for (n = 0; n < 4; n++)
			{
				yy[n]--;
			}
		}
	}
}

 6.固定的方块显示

由于xx,yy只能代表一个方块,而且在重新生成方块时他们又会被重新赋值,所以已经被固定的方块可以通过axis代表状态的这个数组显示出来,在上面的代码中,已经被固定的方块被固定的那几个位置的状态0被赋值到了axis,问题就是我们要如何通过这个数组显示出那些被固定住的方块。这就体现我把状态设为1和0的原因了。

我们通常传给单片机的数据都是16进制,原因是方便简单,这里我要传的是10进制的数。

这里我们又需要定义一个数组trans[8]用来存放col值

uchar trans[8] = { 0 };
void displayfixed()
{
	uchar i;
	for (i = 0; i < 8; i++)
	{
		trans[i] = axis[0][i] * 128 + axis[1][i] * 64 + axis[2][i] * 32 + axis[3][i] * 16 + axis[4][i] * 8 + axis[5][i] * 4 + axis[6][i] * 2 + axis[7][i] * 1;//将col值运算出来存入trans中,并传给点阵屏
		SendByte(trans[i]);
		SendByte(coory[i]);
		R_CLK = 1;
		R_CLK = 0;
	}
}

这边其实又用到了coory[],这里代表的是row的值,这样行选值和列选值都传进去了,只要把函数再放进中断里面就行了。 

7.方块的左右移动

这个要注意不能越界,也就是左右边界,所以需要加下面的if判断

void left()
{
	uchar i;
	if (xx[0] >= 2 && xx[1] >= 2 && xx[2] >= 2 && xx[3] >= 2)
		for (i = 0; i < 4; i++)
		{
			xx[i]++;
		}
}

void right()
{
	uchar i;
	if (xx[0] <= 7 && xx[1] <= 7 && xx[2] <= 7 && xx[3] <= 7)
		for (i = 0; i < 4; i++)
		{
			xx[i]++;
		}
}

8.键值的判断与执行 

void scan()
{
	if (key == 1)
	{
		left();
		key = 5;
	}
	if (key == 2)
	{
		Dextrorotary();
		key = 5;
	}
	if (key == 4)
	{
		right();
		key = 5;
	}
}

9.方块的旋转 

这个我想不出更好的办法了,只能一个个写,挺费时间的,而且代码也很繁琐,这里用的办法就是一个一个分析我以第一个L形为例。加了if是因为如果在右边界,这个方块是不能转的,一转方块的一个脚就会出界,下面的if也是同样的道理,所以加了来限制一下,原理就是把第一个图形的样子通过坐标平移,一顿操作将第一个图形的样子变成第二个图形的样子,然后由于样子变了,所以ran也要变,因为ran的每一个值都代表一个图形。这里可以根据上面的那些图形编程。

void Dextrorotary()
{
	switch (ran)
	{
	case 1:if (xx[0] + 2 <= 8)xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] + 1; xx[3] = xx[3] + 2; yy[3] = yy[3] - 1; ran = 2; break;
	case 2:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 3; break;
	case 3:if (xx[0] - 2 >= 1)xx[0] = xx[0] - 2; xx[1] = xx[1] - 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 2; yy[3] = yy[3] - 1; ran = 4; break;
	case 4:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 1; break;
	case 5:if (xx[0] + 2 <= 8)xx[2] = xx[2] + 1; yy[2] = yy[2] - 1; xx[3] = xx[3] - 1; yy[3] = yy[3] - 1; ran = 6; break;
	case 6:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 2; yy[2] = yy[2] + 2; xx[3] = xx[3] + 1; yy[3] = yy[3] + 1; ran = 7; break;
	case 7:if (xx[0] - 1 >= 1)xx[0] = xx[0] + 1; xx[1] = xx[1] - 1; yy[2] = yy[2] - 1; yy[3] = yy[3] - 1; ran = 8; break;
	case 8:xx[0] = xx[0] - 1; xx[1] = xx[1] + 2; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[3] = yy[3] + 1; ran = 5; break;
	case 9:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 10; break;
	case 10:if (xx[0] - 1 >= 1)xx[1] = xx[1] - 1; xx[2] = xx[2] - 1; xx[3] = xx[3] + 1; yy[3] = yy[3] - 1; ran = 11; break;
	case 11:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] + 1; yy[3] = yy[3] + 1; ran = 12; break;
	case 12:xx[0] = xx[0] - 1; xx[1] = xx[1] + 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 1; yy[3] = yy[3] - 1; ran = 9; break;
	case 13:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] + 2; xx[3] = xx[3] + 1; yy[3] = yy[3] + 1; ran = 14; break;
	case 14:if (xx[0] - 1 >= 1)xx[1] = xx[1] + 1; yy[1] = yy[1] - 1; xx[2] = xx[2] - 2; xx[3] = xx[3] - 1; yy[3] = yy[3] - 1; ran = 13; break;
	case 15:xx[0] = xx[0] + 2; xx[1] = xx[1] + 1; yy[1] = yy[1] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 16; break;
	case 16:xx[0] = xx[0] + 2; yy[1] = yy[1] + 1; xx[2] = xx[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 15; break;
	case 17:xx[0] = xx[0] + 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 2; xx[3] = xx[3] - 2; yy[3] = yy[3] + 3; ran = 18; break;
	case 18:if (xx[0] - 1 >= 1 && xx[0] + 2 <= 8)xx[0] = xx[0] - 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 2; xx[3] = xx[3] + 2; yy[3] = yy[3] - 3; ran = 17; break;
	}
}

 10.总代码

#include <reg52.h>
#include <stdlib.h>
#include <intrins.h>
#define uint unsigned int
#define uchar unsigned char

sbit key_s2 = P3 ^ 0;
sbit key_s3 = P3 ^ 1;
sbit key_s4 = P3 ^ 2;
sbit key_s5 = P3 ^ 3;
sbit DIO = P3 ^ 4;
sbit S_CLK = P3 ^ 5;
sbit R_CLK = P3 ^ 6;

uchar key;
uchar d;
uchar ran;
uchar a = 1;
uchar m = 0;
uchar xx[4];
uchar yy[4];
uchar axis[8][9] = { 0 };
uchar trans[8] = { 0 };
uchar coorx[8] = { 0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe };
uchar coory[8] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };

void delay(uint z)
{
	uint x, y;
	for (x = z; x > 0; x--)
		for (y = 114; y > 0; y--);
}

void KeyScan()
{
	if (key_s2 == 0)
	{
		delay(10);
		if (key_s2 == 0)
		{
			key = 1;
		}
	}
	if (key_s3 == 0)
	{
		delay(10);
		if (key_s3 == 0)
		{
			key = 2;
		}
	}
	if (key_s4 == 0)//这一个按键其实没用到
	{
		delay(10);
		if (key_s4 == 0)
		{
			key = 3;
		}
	}
	if (key_s5 == 0)
	{
		delay(10);
		if (key_s5 == 0)
		{
			key = 4;
		}
	}
}

void SendByte(uchar dat)
{
	uchar i;
	S_CLK = 0;
	R_CLK = 0;
	for (i = 0; i < 8; i++)
	{
		if (dat & 0x01)
			DIO = 1;
		else
			DIO = 0;
		S_CLK = 1;
		S_CLK = 0;
		dat >>= 1;
	}
}

void displaymove(uchar dat1, uchar dat2)
{
	SendByte(dat1);
	SendByte(dat2);
	R_CLK = 1;
	R_CLK = 0;
}

void displayfixed()
{
	uchar i;
	for (i = 0; i < 8; i++)
	{
		trans[i] = axis[0][i] * 128 + axis[1][i] * 64 + axis[2][i] * 32 + axis[3][i] * 16 + axis[4][i] * 8 + axis[5][i] * 4 + axis[6][i] * 2 + axis[7][i] * 1;//将col值运算出来存入trans中,并传给点阵屏
		SendByte(trans[i]);
		SendByte(coory[i]);
		R_CLK = 1;
		R_CLK = 0;
	}
}

void Random()
{
	ran = rand() % 19 + 1;
	switch (ran)
	{
	case 1:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 2:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 6; yy[3] = 10; break;
	case 3:xx[0] = 5; yy[0] = 9; xx[1] = 5; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 5; yy[3] = 11; break;
	case 4:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 5; yy[2] = 9; xx[3] = 5; yy[3] = 10; break;
	case 5:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 6:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 6; yy[2] = 9; xx[3] = 4; yy[3] = 10; break;
	case 7:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 5; yy[3] = 11; break;
	case 8:xx[0] = 5; yy[0] = 9; xx[1] = 3; yy[1] = 10; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 9:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 6; yy[2] = 9; xx[3] = 5; yy[3] = 10; break;
	case 10:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 11:xx[0] = 4; yy[0] = 9; xx[1] = 3; yy[1] = 10; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 12:xx[0] = 5; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 13:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 3; yy[2] = 10; xx[3] = 4; yy[3] = 10; break;
	case 14:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 5; yy[3] = 11; break;
	case 15:xx[0] = 5; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 5; yy[2] = 10; xx[3] = 4; yy[3] = 11; break;
	case 16:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	case 17:xx[0] = 3; yy[0] = 9; xx[1] = 4; yy[1] = 9; xx[2] = 5; yy[2] = 9; xx[3] = 6; yy[3] = 9; break;
	case 18:xx[0] = 4; yy[0] = 9; xx[1] = 4; yy[1] = 10; xx[2] = 4; yy[2] = 11; xx[3] = 4; yy[3] = 12; break;
	case 19:xx[0] = 4; yy[0] = 9; xx[1] = 5; yy[1] = 9; xx[2] = 4; yy[2] = 10; xx[3] = 5; yy[3] = 10; break;
	}
}

void down()
{
	uchar n;
	if (yy[0] <= 1)
	{
		for (n = 0; n < 4; n++)
		{
			axis[xx[n] - 1][yy[n] - 1] = 0;//碰到边界了,此时这四个点的状态置为0,之后会将这个方块显示出来
		}
		Random();//方块停止了,需要重新生成方块
	}
	else
	{
		if (yy[0] <= 9 && yy[1] <= 9 && yy[2] <= 9 && yy[3] <= 9)//约束范围,防止越界
		{
			if (axis[xx[0] - 1][yy[0] - 2] == 1 && axis[xx[1] - 1][yy[1] - 2] == 1 && axis[xx[2] - 1][yy[2] - 2] == 1 && axis[xx[3] - 1][yy[3] - 2] == 1)//判断下一个方块下移过程中是否碰到了已经被固定了的方块,如果碰到就不下降了
			{
				for (n = 0; n < 4; n++)
				{
					yy[n]--;
				}
			}
			else
			{
				for (n = 0; n < 4; n++)
				{
					axis[xx[n] - 1][yy[n] - 1] = 0;//如果方块被固定了,那么这个方块所在的位置的状态就会被赋给axis,便于后续的显示
				}
				Random();
			}
		}
		else
		{
			for (n = 0; n < 4; n++)
			{
				yy[n]--;
			}
		}
	}
}

void left()
{
	uchar i;
	if (xx[0] >= 2 && xx[1] >= 2 && xx[2] >= 2 && xx[3] >= 2)
		for (i = 0; i < 4; i++)
		{
			xx[i]++;
		}
}

void right()
{
	uchar i;
	if (xx[0] <= 7 && xx[1] <= 7 && xx[2] <= 7 && xx[3] <= 7)
		for (i = 0; i < 4; i++)
		{
			xx[i]++;
		}
}

void Dextrorotary()
{
	switch (ran)
	{
	case 1:if (xx[0] + 2 <= 8)xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] + 1; xx[3] = xx[3] + 2; yy[3] = yy[3] - 1; ran = 2; break;
	case 2:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 3; break;
	case 3:if (xx[0] - 2 >= 1)xx[0] = xx[0] - 2; xx[1] = xx[1] - 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 2; yy[3] = yy[3] - 1; ran = 4; break;
	case 4:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 1; break;
	case 5:if (xx[0] + 2 <= 8)xx[2] = xx[2] + 1; yy[2] = yy[2] - 1; xx[3] = xx[3] - 1; yy[3] = yy[3] - 1; ran = 6; break;
	case 6:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 2; yy[2] = yy[2] + 2; xx[3] = xx[3] + 1; yy[3] = yy[3] + 1; ran = 7; break;
	case 7:if (xx[0] - 1 >= 1)xx[0] = xx[0] + 1; xx[1] = xx[1] - 1; yy[2] = yy[2] - 1; yy[3] = yy[3] - 1; ran = 8; break;
	case 8:xx[0] = xx[0] - 1; xx[1] = xx[1] + 2; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[3] = yy[3] + 1; ran = 5; break;
	case 9:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 10; break;
	case 10:if (xx[0] - 1 >= 1)xx[1] = xx[1] - 1; xx[2] = xx[2] - 1; xx[3] = xx[3] + 1; yy[3] = yy[3] - 1; ran = 11; break;
	case 11:xx[0] = xx[0] + 1; xx[1] = xx[1] + 1; xx[2] = xx[2] + 1; yy[3] = yy[3] + 1; ran = 12; break;
	case 12:xx[0] = xx[0] - 1; xx[1] = xx[1] + 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 1; yy[3] = yy[3] - 1; ran = 9; break;
	case 13:xx[1] = xx[1] - 1; yy[1] = yy[1] + 1; xx[2] = xx[2] + 2; xx[3] = xx[3] + 1; yy[3] = yy[3] + 1; ran = 14; break;
	case 14:if (xx[0] - 1 >= 1)xx[1] = xx[1] + 1; yy[1] = yy[1] - 1; xx[2] = xx[2] - 2; xx[3] = xx[3] - 1; yy[3] = yy[3] - 1; ran = 13; break;
	case 15:xx[0] = xx[0] + 2; xx[1] = xx[1] + 1; yy[1] = yy[1] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 16; break;
	case 16:xx[0] = xx[0] + 2; yy[1] = yy[1] + 1; xx[2] = xx[2] + 1; xx[3] = xx[3] - 1; yy[3] = yy[3] + 1; ran = 15; break;
	case 17:xx[0] = xx[0] + 1; yy[1] = yy[1] + 1; xx[2] = xx[2] - 1; yy[2] = yy[2] + 2; xx[3] = xx[3] - 2; yy[3] = yy[3] + 3; ran = 18; break;
	case 18:if (xx[0] - 1 >= 1 && xx[0] + 2 <= 8)xx[0] = xx[0] - 1; yy[1] = yy[1] - 1; xx[2] = xx[2] + 1; yy[2] = yy[2] - 2; xx[3] = xx[3] + 2; yy[3] = yy[3] - 3; ran = 17; break;
	}
}

void Clear()
{
	uchar i;
	for (i = 0; i < 8; i++)
	{
		if (axis[0][i] + axis[1][i] + axis[2][i] + axis[3][i] + axis[4][i] + axis[5][i] + axis[6][i] + axis[7][i] == 0)
		{
			uchar j, k;
			for (j = i; j < 8; j++)
			{
				for (k = 0; k < 8; k++)
				{
					axis[k][j] = axis[k][j + 1];
				}
			}
		}
	}
}

void scan()
{
	if (key == 1)
	{
		left();
		key = 5;
	}
	if (key == 2)
	{
		Dextrorotary();
		key = 5;
	}
	if (key == 4)
	{
		right();
		key = 5;
	}
}

void timer0Init()
{
	EA = 1;
	ET0 = 1;
	TR0 = 1;
	TMOD = 0X01;
	TH0 = 0XDD;
	TL0 = 0XFF;
}

void main()
{
	uchar j, k, i;
	for (j = 0; j < 8; j++)
		for (k = 0; k < 9; k++)
			axis[j][k] = 1;//8×8点阵屏上面的每一个点都初始化为1(1代表点亮,0代表熄灭),这样便于后面显示
	timer0Init();//定时器0初始化
	while (1)
	{
		scan();//判断键值,并通过键值执行相应指令
		if (a)
		{
			Random();//生成一个随机图形(仅生成一次)
			a = 0;
		}
		if (m == 40)
		{
			down();//定时器没定时一次m++,m到40的时候图形下降一格
			m = 0;
		}
		Clear();//判断有没有一行全部点亮,有就消除
		for (i = 0; i < 8; i++)
		{
			if (axis[i][8] == 0)//判断游戏结束
				return;
		}
	}
}

void timer0() interrupt 1
{
	TH0 = 0XDD;
	TL0 = 0XFF;
	m++;
	KeyScan();//按键扫描
	for (d = 0; d < 4; d++)
	{
		if (yy[d] <= 8 && yy[d] >= 1)
			displaymove(coorx[xx[d] - 1], coory[yy[d] - 1]);//对于活动的图形的显示
	}
	displayfixed();//对于已经固定的图形显示
}

总结

希望对你们有所帮助,如有不足还望指正。

物联沃分享整理
物联沃-IOTWORD物联网 » 详解51单片机点阵屏如何实现俄罗斯方块游戏

发表评论