基于51单片机的俄罗斯方块小游戏8X8点阵 proteus仿真原理图程序设计

前言

之前讲过基于LCD12864的俄罗斯方块小游戏,接下来讲一讲基于8X8点阵的俄罗斯方块

硬件设计

  • MCU同样是基于C51、
  • 两个8X8点阵组合成游戏显示区域
  • 4位数码管作为分数记分牌

仿真图:
在这里插入图片描述

程序设计

#include<reg52.h>
#include<stdlib.h>
#include<math.h>
#define uchar unsigned char
sbit slock=P2^7;					//译码器输出使能端
sbit upkey=P2^3;					//“旋转图形/向上”按键
sbit leftkey=P2^1;					//“左移/向左”按键
sbit rightkey=P2^2;					//“右移/向右”按键
sbit downkey=P2^0;					//“快速下移/向下”按键
sbit duan=P2^5;						//数码管段选信号所用锁存器的锁存允许端
sbit wei=P2^6;						//数码管位选信号所用锁存器的锁存允许端
sbit startsuspendkey=P2^4;			//“开始/暂停/继续”多功能切换按键
/***********************************图形编码机制介绍**************************************
1.由于俄罗斯方块图形的宽度和高度最多只有四位,所以要以4X4为基本单元。
2.硬件采用16行扫描、8位送显示信号
3.各个图形的宽度不一致,所以要人为给图形设定居中位置。
  若图形宽度为偶数可直接将其居中,若为奇数则靠左居中。
4.由于图形需要旋转,所以由基本的图形会衍生出另外3种图形。
5.因此每个图形应该给定4个8位的二进制码,并放入一个二维数组里。
6.经典俄罗斯方块游戏里有19种不同形状的方块,包括旋转得到的。
7.数组的第一个下标为该图形的编号
*****************************************************************************************/
uchar code allshape[19][4]={0x00,0x00,0x18,0x18,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x3c,
							0x00,0x08,0x18,0x10,0x00,0x00,0x30,0x18,0x00,0x10,0x18,0x08,
							0x00,0x00,0x18,0x30,0x00,0x08,0x08,0x18,0x00,0x00,0x38,0x08,
							0x00,0x18,0x10,0x10,0x00,0x00,0x20,0x38,0x00,0x10,0x10,0x18,
							0x00,0x00,0x08,0x38,0x00,0x18,0x08,0x08,0x00,0x00,0x38,0x20,
							0x00,0x00,0x10,0x38,0x00,0x08,0x18,0x08,0x00,0x00,0x38,0x10,
							0x00,0x10,0x18,0x10};
/****************************************************************************************/
uchar code number[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};	//数码管数形显示编码
uchar code weima[4]={0x01,0x02,0x04,0x08};									//位选信号编码,方便写循环使用
char shapewidth[19]={2,1,4,2,3,2,3,2,3,2,3,2,3,2,3,3,2,3,2};				//各个图形的宽度属性,用于判断左移和右移的步格数上限
char shaperotate[19]={0,2,1,4,3,6,5,8,9,10,7,12,13,14,11,16,17,18,15};		//旋转图形时,用于改变图形的编号以实现图形的切换
uchar staticdata[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff};			//用于存储方块降落后固定显示的图形信息
uchar rate[5]={0,1,3,6,10};													//规定一次性消掉的行数的分数奖励机制


/****************************************全局变量声明************************************/
char y;					//方块位置属性:底部下落的高度,y=0时:刚刚出现,y=15时:下落到屏幕最底部
char shapenum;			//方块形状属性:从0到18
int left; 				//方块位置属性:方块偏离居中位置的格数,不同的方块left值的上限不同
int mark;				//玩家分数变量
int speed;				//方块下落速度变量
int initialspeed;		//方块下落的初始速度
int systemspeed;		//系统下落速度,此值会随着玩家分数的增加而减小,相应的下落速度会增大
int fastspeed;			//当用户按下down键时,方块下落速度为此值
int k;					//一个全局循环变量,“帧数”变量
int startcontrol=1;		//开始画面状态指示变量,为1时说明程序进入开机欢迎界面
int suspendcontrol=0;	//游戏暂停与游戏继续画面状态指示变量,为1说明处在暂停界面,为0说明处在继续画面
int randnum;			//随机数变量,用于产生随机方块
/****************************************************************************************/


/****************************************函数声明****************************************/
void delayms(int);				//粗略延时函数
uchar move(uchar,int);			//对二进制码实行移位,可为负值
void shapedisplay();			//对点阵扫描一场,对数码管扫描一场,用于显示图形和数字
void keyscan();					//对所有键盘扫描一次,并执行相应运算和操作
uchar check(char,int);			//用于检查方块将要下落的位置或是将要旋转的位置是否有障碍
uchar shapedisappear();			//用于消行,返回一次性消掉的行数
numberdisplay(int amark);		//用于四位数字显示
void startimage();				//游戏等待开始画面函数
void overimage();				//游戏结束后的画面
void dataset();					//对数据初始化,为游戏重新开始做准备
/****************************************************************************************/


/*****************************************主函数*****************************************/
void main()
{
	char j;
	startimage();					//进入开机,函数内有键盘扫描,只有按下“开始”键会退出函数,否则不退出
	dataset();						//对数据进行初始化
	while(1){						//进入大循环
		k=speed;					//确定显示的帧数
		while(k--){
			keyscan();				//扫描键盘,放入高速循环语句中提高键盘的响应速度,并检测此时用户是否有相应请求
			shapedisplay();			//显示图形和数字
		}
		y++;						//图形下落一格
		if(check(shapenum,left)){	//在没有显示之前判断将要下落的位置是否有障碍物,如果有障碍就进入到if语句中
			if(y==1){				//如果y=1;说明方块刚出现就遇到障碍物了,这时游戏需结束
				overimage();		//进入游戏结束画面,此函数内没有键盘扫描,运行一段时间会自动退出
				startimage();		//又进入开机画面
				dataset();			//对数据进行初始化,将前一用户数据清零	
			}
			else{													//遇到障碍物,但还不至于图形不能出现
				y--;												//y回到原值
				for(j=0;j<4;j++){									//将下落形状的值赋给固定图形,形成停留显示的效果
					staticdata[y+j]+=move(allshape[shapenum][j],left);
				}
				mark+=rate[shapedisappear()];						//消掉已拼满的函数,并记录所得分数
				y=0;												//为下一个方块赋属性值:从第一行出现
				left=0;												//为下一个方块赋属性值:居中显示
				randnum=rand()%19;shapenum=randnum;					//为下一个方块赋属性值:给定形状
				systemspeed=initialspeed-10*(mark/40);				//计算相应分数下的系统速度值,分数越高,速度越快
				speed=systemspeed;									//将此值赋给速度控制量
			}
		}
	}
}
/****************************************************************************************/


/***************************************自定义函数***************************************/
void delayms(int xms)		  	//粗略的延时函数
{	
	int i,j;
	for(i=xms;i>0;i--)
		for(j=110;j>0;j--);
}
/****************************************************************************************/
uchar move(uchar aa,int anum)	//移位函数	
{							 	
	if(anum>=0)
		aa<<=anum;
	else
		aa>>=(-anum);
	return aa;
}
/****************************************************************************************/
void shapedisplay()				//显示函数
{
	uchar j;
	for(j=y<3?3-y:0;j<4;j++){	//显示动态方块		
		slock=1;P1=j+y-3;P3=move(allshape[shapenum][j],left);
		slock=0;delayms(1);P3=0x00;
	}
	for(j=0;j<16;j++){			//显示静态方块
		slock=1;P1=j;P3=staticdata[j+3];
		slock=0;delayms(1);P3=0x00;
	}
	numberdisplay(mark);		//分数显示	
}

原文: http://www.jh-tec.cn/archives/8302

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值