源程序:
- /*****************************************************************************************
- 名称:《基于8052单片机和8X16点阵屏俄罗斯方块游戏板》
- 时间:05月23日17时
- 单位:武汉理工大学信息学院电子1003班
- 作者:颜百千
- *****************************************************************************************/
- #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); //分数显示
- }
- /****************************************************************************************/
- numberdisplay(int amark) //大数拆分并显示,带去无效零功能
- {
- char i;
- uchar num[4];
- num[0]=amark/1000%10;num[1]=amark/100%10;num[2]=amark/10%10;num[3]=amark%10;
- if(amark<10){ //显示一位数
- for(i=3;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else if(amark<100){ //显示两位数
- for(i=2;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else if(amark<1000){ //显示三位数
- for(i=1;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- else{ //显示四位数
- for(i=0;i<4;i++){
- P0=0xff;
- duan=1;
- P0=number[num[i]];
- duan=0;
- P0=0x00;
- wei=1;
- P0=weima[i];
- wei=0;
- delayms(1);
- wei=1;
- P0=0x00;
- wei=0;
- }
- }
- return 0;
- }
- /****************************************************************************************/
- void keyscan() //键盘扫锚并执行用户输入的指令
- {
- if(leftkey==0&&(left<(shapewidth[shapenum]<3?3:2))&&!check(shapenum,left+1)&&
- startcontrol==0&&suspendcontrol==0){
- delayms(10); //按键无效条件:1.左移超边缘;2.左移遇障碍;3.处在欢迎界面;4.处在暂停界面
- if(leftkey==0){
- left++; //按键命令:方块左移一位
- speed=systemspeed;
- while(!leftkey){
- shapedisplay();
- }
- }
- }
- if(rightkey==0&&(left>(shapewidth[shapenum]<3?shapewidth[shapenum]-5:shapewidth[shapenum]-6))&&
- !check(shapenum,left-1)&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按键无效条件:1.右移超边缘;2.右移遇障碍;3.处在欢迎界面;4.处在暂停界面
- if(rightkey==0){
- left--; //按键命令:方块右移一位
- speed=systemspeed;
- while(!rightkey){
- shapedisplay();
- }
- }
- }
- if(upkey==0&&!check(shaperotate[shapenum],left)&&(left<(shapewidth[shaperotate[shapenum]]<3?4:3))
- &&(left>(shapewidth[shaperotate[shapenum]]<3?shapewidth[shaperotate[shapenum]]-6:shapewidth[shapenum]-7))
- &&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按键无效条件:1.翻转超左右边缘;2.翻转遇障碍;3.处在欢迎界面;4.进入暂停界面
- if(upkey==0){
- shapenum=shaperotate[shapenum]; //按键命令:将翻转后的图形编号赋给要显示的图形编号
- speed=systemspeed;
- while(!upkey){
- shapedisplay();
- }
- }
- }
- if(downkey==0&&speed!=fastspeed&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按键无效条件:1.已经进入快速下降状态;2.处在欢迎界面;3.进入暂停界面
- if(downkey==0){
- speed=fastspeed; //按键命令:将方块下落速度加快
- k=speed;
- while(!downkey){
- shapedisplay();
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==1&&suspendcontrol==0){
- delayms(10); //按键有效条件:1.处在开始欢迎界面;2.处在暂停界面
- if(startsuspendkey==0){
- startcontrol=0;
- suspendcontrol=0; //按键命令:使进入继续游戏状态
- while(!startsuspendkey){
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==0){
- delayms(10); //按键无效条件:1.处在开始欢迎界面;2.处在暂停状态
- if(startsuspendkey==0){
- suspendcontrol=1;
- startcontrol=0; //按键命令:状态切换,使进入暂停状态
- while(!startsuspendkey){
- shapedisplay();
- }
- while(suspendcontrol){
- shapedisplay();
- keyscan(); //等待结束暂停状态的命令
- }
- }
- }
- if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==1){
- delayms(10); //按键有效条件:处在暂停界面
- if(startsuspendkey==0){
- suspendcontrol=0;
- startcontrol=0; //按键命令:状态切换,使进入继续游戏状态
- while(!startsuspendkey){
- shapedisplay();
- }
- }
- }
- }
- /****************************************************************************************/
- uchar check(char ashapenum,int aleft) //判断方块是否会遇到障碍物
- {
- char i=3,j=0;
- while(!j&&i>=0){
- if((move(allshape[ashapenum][i],aleft)+staticdata[y+i])!=(move(allshape[ashapenum][i],aleft)|staticdata[y+i])){
- j++;
- }
- i--;
- }
- return j; //返回0,说明没有障碍
- }
- /****************************************************************************************/
- uchar shapedisappear() //方块落定后消掉拼满的行,并使没有拼满的行整体下移填补空缺行
- {
- char i,j,r=4;
- for(i=0;i<r;i++){
- if(staticdata[y+3-i]==0xff){
- for(j=y+3-i;j>0;j--){
- staticdata[j]=staticdata[j-1];
- }
- i--,r--;
- }
- }
- return 4-r; //函数返回一次性消掉的行的数目
- }
- /****************************************************************************************/
- void startimage() //开机欢迎画面,在没有按键作用的时候会不断执行
- {
- uchar i,j;
- startcontrol=1;
- while(startcontrol){
- for(i=10;i>0;i--){
- for(j=0;j<16;j+=2){
- slock=1;P1=j;P3=0xaa;
- slock=0;delayms(1);P3=0x00;
- }
- for(j=1;j<16;j+=2){
- slock=1;P1=j;P3=0x55;
- slock=0;delayms(1);P3=0x00;
- }
- keyscan(); //随时响应用户输入
- }
- for(i=10;i>0;i--){
- for(j=1;j<16;j+=2){
- slock=1;P1=j;P3=0xaa;
- slock=0;delayms(1);P3=0x00;
- }
- for(j=0;j<16;j+=2){
- slock=1;P1=j;P3=0x55;
- slock=0;delayms(1);P3=0x00;
- }
- keyscan(); //随时响应用户输入
- }
- }
- }
- /****************************************************************************************/
- void overimage() //游戏结束画面,分数会强制闪烁8次,并自动结束
- {
- int i,j;
- for(j=0;j<8;j++){
- for(i=0;i<200;i++){
- numberdisplay(mark);
- }
- delayms(500);
- }
- }
- /****************************************************************************************/
- void dataset() //数据全部清零,重新开始游戏
- {
- char j;
- y=0;
- left=0;
- shapenum=0;
- initialspeed=100;
- speed=initialspeed;
- systemspeed=initialspeed;
- fastspeed=5;
- randnum=rand()%19;
- shapenum=randnum;
- mark=0;
- for(j=0;j<19;j++){ //清除点阵上的显示数据
- staticdata[j]=0;
- }
- }
- /****************************************************************************************/
复制代码 |