找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 17591|回复: 17
收起左侧

点阵俄罗斯方块游戏板 详细开发过程

  [复制链接]
ID:140725 发表于 2016-10-12 13:08 | 显示全部楼层 |阅读模式
    我和大家一样都喜欢电子设计这个领域,喜欢编编程序,调调代码,焊焊电路,秀秀作品。

    大二的时候寝室有个同学搞了个很大的点阵屏,他说目的是让他显示汉字以及编写各种炫目的汉字显示动画。这时我就有了用点阵屏作为简易显示屏来编写一个俄罗斯方块游戏的想法。点阵显示都是刚接触单片机的人再熟悉不过的东西了,所以基本思想大家都懂,我就不详细唠叨了。

    花了半个多月没事就背着电脑往图书馆赶,终于做出来了。当然这个作品也参加了院里的比赛,老师同学都觉得不错,我也从此迷上了电子设计,我也特别喜欢交友,希望看到文章的都能和我成为朋友

本设计会详细展示PPT内容,我也会把源代码上传,还有工程文件以及用软件仿真的文件一并公开。
    先给个成品大家看看有个大致的了解吧!
0.png
    233004q9v9qyx4z94fhvhv.jpg.thumb.jpg

    下面是一段跟我同乡同学讲解我作品的视频,因为是同乡所以说的是家乡湖北话,不知道大家能听懂不!




这个视频是我操作仿真软件时的效果,因为是屏幕录像,没有声音,也比较短



0.png 0.png 0.png
    先把文件链接给一下吧:

      1.C程序源代码:   C51程序.rar (14.59 KB, 下载次数: 96)

评分

参与人数 1黑币 +5 收起 理由
kruba + 5 很给力!

查看全部评分

回复

使用道具 举报

ID:140725 发表于 2016-10-12 13:10 | 显示全部楼层
源程序:
  1. /*****************************************************************************************
  2. 名称:《基于8052单片机和8X16点阵屏俄罗斯方块游戏板》
  3. 时间:05月23日17时
  4. 单位:武汉理工大学信息学院电子1003班
  5. 作者:颜百千
  6. *****************************************************************************************/
  7. #include<reg52.h>
  8. #include<stdlib.h>
  9. #include<math.h>
  10. #define uchar unsigned char
  11. sbit slock=P2^7;                                        //译码器输出使能端
  12. sbit upkey=P2^3;                                        //“旋转图形/向上”按键
  13. sbit leftkey=P2^1;                                        //“左移/向左”按键
  14. sbit rightkey=P2^2;                                        //“右移/向右”按键
  15. sbit downkey=P2^0;                                        //“快速下移/向下”按键
  16. sbit duan=P2^5;                                                //数码管段选信号所用锁存器的锁存允许端
  17. sbit wei=P2^6;                                                //数码管位选信号所用锁存器的锁存允许端
  18. sbit startsuspendkey=P2^4;                        //“开始/暂停/继续”多功能切换按键
  19. /***********************************图形编码机制介绍**************************************
  20. 1.由于俄罗斯方块图形的宽度和高度最多只有四位,所以要以4X4为基本单元。
  21. 2.硬件采用16行扫描、8位送显示信号
  22. 3.各个图形的宽度不一致,所以要人为给图形设定居中位置。
  23.   若图形宽度为偶数可直接将其居中,若为奇数则靠左居中。
  24. 4.由于图形需要旋转,所以由基本的图形会衍生出另外3种图形。
  25. 5.因此每个图形应该给定4个8位的二进制码,并放入一个二维数组里。
  26. 6.经典俄罗斯方块游戏里有19种不同形状的方块,包括旋转得到的。
  27. 7.数组的第一个下标为该图形的编号
  28. *****************************************************************************************/
  29. uchar code allshape[19][4]={0x00,0x00,0x18,0x18,0x10,0x10,0x10,0x10,0x00,0x00,0x00,0x3c,
  30.                                                         0x00,0x08,0x18,0x10,0x00,0x00,0x30,0x18,0x00,0x10,0x18,0x08,
  31.                                                         0x00,0x00,0x18,0x30,0x00,0x08,0x08,0x18,0x00,0x00,0x38,0x08,
  32.                                                         0x00,0x18,0x10,0x10,0x00,0x00,0x20,0x38,0x00,0x10,0x10,0x18,
  33.                                                         0x00,0x00,0x08,0x38,0x00,0x18,0x08,0x08,0x00,0x00,0x38,0x20,
  34.                                                         0x00,0x00,0x10,0x38,0x00,0x08,0x18,0x08,0x00,0x00,0x38,0x10,
  35.                                                         0x00,0x10,0x18,0x10};
  36. /****************************************************************************************/
  37. uchar code number[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};        //数码管数形显示编码
  38. uchar code weima[4]={0x01,0x02,0x04,0x08};                                                                        //位选信号编码,方便写循环使用
  39. char shapewidth[19]={2,1,4,2,3,2,3,2,3,2,3,2,3,2,3,3,2,3,2};                                //各个图形的宽度属性,用于判断左移和右移的步格数上限
  40. char shaperotate[19]={0,2,1,4,3,6,5,8,9,10,7,12,13,14,11,16,17,18,15};                //旋转图形时,用于改变图形的编号以实现图形的切换
  41. uchar staticdata[20]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0xff};                        //用于存储方块降落后固定显示的图形信息
  42. uchar rate[5]={0,1,3,6,10};                                                                                                        //规定一次性消掉的行数的分数奖励机制


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


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


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


  104. /***************************************自定义函数***************************************/
  105. void delayms(int xms)                          //粗略的延时函数
  106. {       
  107.         int i,j;
  108.         for(i=xms;i>0;i--)
  109.                 for(j=110;j>0;j--);
  110. }
  111. /****************************************************************************************/
  112. uchar move(uchar aa,int anum)        //移位函数       
  113. {                                                                
  114.         if(anum>=0)
  115.                 aa<<=anum;
  116.         else
  117.                 aa>>=(-anum);
  118.         return aa;
  119. }
  120. /****************************************************************************************/
  121. void shapedisplay()                                //显示函数
  122. {
  123.         uchar j;
  124.         for(j=y<3?3-y:0;j<4;j++){        //显示动态方块               
  125.                 slock=1;P1=j+y-3;P3=move(allshape[shapenum][j],left);
  126.                 slock=0;delayms(1);P3=0x00;
  127.         }
  128.         for(j=0;j<16;j++){                        //显示静态方块
  129.                 slock=1;P1=j;P3=staticdata[j+3];
  130.                 slock=0;delayms(1);P3=0x00;
  131.         }
  132.         numberdisplay(mark);                //分数显示       
  133. }
  134. /****************************************************************************************/
  135. numberdisplay(int amark)                //大数拆分并显示,带去无效零功能
  136. {
  137.         char i;
  138.         uchar num[4];
  139.         num[0]=amark/1000%10;num[1]=amark/100%10;num[2]=amark/10%10;num[3]=amark%10;
  140.         if(amark<10){                                   //显示一位数
  141.                 for(i=3;i<4;i++){
  142.                         P0=0xff;
  143.                         duan=1;
  144.                         P0=number[num[i]];
  145.                         duan=0;
  146.                         P0=0x00;
  147.                         wei=1;
  148.                         P0=weima[i];
  149.                         wei=0;
  150.                         delayms(1);
  151.                         wei=1;
  152.                         P0=0x00;
  153.                         wei=0;
  154.                 }
  155.         }
  156.         else if(amark<100){                          //显示两位数
  157.                 for(i=2;i<4;i++){
  158.                         P0=0xff;
  159.                         duan=1;
  160.                         P0=number[num[i]];
  161.                         duan=0;
  162.                         P0=0x00;
  163.                         wei=1;
  164.                         P0=weima[i];
  165.                         wei=0;
  166.                         delayms(1);
  167.                         wei=1;
  168.                         P0=0x00;
  169.                         wei=0;
  170.                 }
  171.         }
  172.         else if(amark<1000){                  //显示三位数
  173.                 for(i=1;i<4;i++){
  174.                         P0=0xff;
  175.                         duan=1;
  176.                         P0=number[num[i]];
  177.                         duan=0;
  178.                         P0=0x00;
  179.                         wei=1;
  180.                         P0=weima[i];
  181.                         wei=0;
  182.                         delayms(1);
  183.                         wei=1;
  184.                         P0=0x00;
  185.                         wei=0;
  186.                 }
  187.         }
  188.         else{                                                //显示四位数
  189.                 for(i=0;i<4;i++){
  190.                         P0=0xff;
  191.                         duan=1;
  192.                         P0=number[num[i]];
  193.                         duan=0;
  194.                         P0=0x00;
  195.                         wei=1;
  196.                         P0=weima[i];
  197.                         wei=0;
  198.                         delayms(1);
  199.                         wei=1;
  200.                         P0=0x00;
  201.                         wei=0;
  202.                 }  
  203.         }          
  204.         return 0;
  205. }
  206. /****************************************************************************************/
  207. void keyscan()                                         //键盘扫锚并执行用户输入的指令
  208. {
  209.         if(leftkey==0&&(left<(shapewidth[shapenum]<3?3:2))&&!check(shapenum,left+1)&&
  210.            startcontrol==0&&suspendcontrol==0){
  211.                 delayms(10);                        //按键无效条件:1.左移超边缘;2.左移遇障碍;3.处在欢迎界面;4.处在暂停界面
  212.                 if(leftkey==0){       
  213.                         left++;                                //按键命令:方块左移一位
  214.                         speed=systemspeed;
  215.                         while(!leftkey){                                                       
  216.                                 shapedisplay();                               
  217.                         }
  218.                 }
  219.         }
  220.         if(rightkey==0&&(left>(shapewidth[shapenum]<3?shapewidth[shapenum]-5:shapewidth[shapenum]-6))&&
  221.            !check(shapenum,left-1)&&startcontrol==0&&suspendcontrol==0){
  222.                 delayms(10);                           //按键无效条件:1.右移超边缘;2.右移遇障碍;3.处在欢迎界面;4.处在暂停界面
  223.                 if(rightkey==0){       
  224.                         left--;                                //按键命令:方块右移一位
  225.                         speed=systemspeed;
  226.                         while(!rightkey){                       
  227.                                 shapedisplay();       
  228.                         }
  229.                 }
  230.         }
  231.         if(upkey==0&&!check(shaperotate[shapenum],left)&&(left<(shapewidth[shaperotate[shapenum]]<3?4:3))
  232.            &&(left>(shapewidth[shaperotate[shapenum]]<3?shapewidth[shaperotate[shapenum]]-6:shapewidth[shapenum]-7))
  233.            &&startcontrol==0&&suspendcontrol==0){
  234.                 delayms(10);                        //按键无效条件:1.翻转超左右边缘;2.翻转遇障碍;3.处在欢迎界面;4.进入暂停界面
  235.                 if(upkey==0){       
  236.                         shapenum=shaperotate[shapenum];        //按键命令:将翻转后的图形编号赋给要显示的图形编号
  237.                         speed=systemspeed;
  238.                         while(!upkey){                       
  239.                                 shapedisplay();
  240.                         }
  241.                 }
  242.         }
  243.         if(downkey==0&&speed!=fastspeed&&startcontrol==0&&suspendcontrol==0){
  244.                 delayms(10);                        //按键无效条件:1.已经进入快速下降状态;2.处在欢迎界面;3.进入暂停界面
  245.                 if(downkey==0){       
  246.                         speed=fastspeed;        //按键命令:将方块下落速度加快
  247.                         k=speed;
  248.                         while(!downkey){
  249.                                 shapedisplay();
  250.                         }
  251.                 }
  252.         }
  253.         if(startsuspendkey==0&&startcontrol==1&&suspendcontrol==0){
  254.                 delayms(10);                           //按键有效条件:1.处在开始欢迎界面;2.处在暂停界面
  255.                 if(startsuspendkey==0){
  256.                         startcontrol=0;                          
  257.                         suspendcontrol=0;        //按键命令:使进入继续游戏状态
  258.                         while(!startsuspendkey){
  259.                         }
  260.                 }       
  261.         }
  262.         if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==0){
  263.                 delayms(10);                         //按键无效条件:1.处在开始欢迎界面;2.处在暂停状态
  264.                 if(startsuspendkey==0){
  265.                         suspendcontrol=1;       
  266.                         startcontrol=0;                //按键命令:状态切换,使进入暂停状态
  267.                         while(!startsuspendkey){
  268.                                 shapedisplay();       
  269.                         }
  270.                         while(suspendcontrol){
  271.                                 shapedisplay();
  272.                                 keyscan();                //等待结束暂停状态的命令
  273.                         }                                                       
  274.                 }
  275.         }
  276.         if(startsuspendkey==0&&startcontrol==0&&suspendcontrol==1){
  277.                 delayms(10);                        //按键有效条件:处在暂停界面
  278.                 if(startsuspendkey==0){       
  279.                         suspendcontrol=0;
  280.                         startcontrol=0;                //按键命令:状态切换,使进入继续游戏状态
  281.                         while(!startsuspendkey){
  282.                                 shapedisplay();
  283.                         }                               
  284.                 }
  285.         }
  286. }
  287. /****************************************************************************************/
  288. uchar check(char ashapenum,int aleft)        //判断方块是否会遇到障碍物
  289. {
  290.         char i=3,j=0;
  291.         while(!j&&i>=0){
  292.                 if((move(allshape[ashapenum][i],aleft)+staticdata[y+i])!=(move(allshape[ashapenum][i],aleft)|staticdata[y+i])){
  293.                         j++;
  294.                 }
  295.                 i--;
  296.         }
  297.         return j;                                                           //返回0,说明没有障碍
  298. }
  299. /****************************************************************************************/
  300. uchar shapedisappear()                                           //方块落定后消掉拼满的行,并使没有拼满的行整体下移填补空缺行
  301. {
  302.         char i,j,r=4;
  303.         for(i=0;i<r;i++){
  304.                 if(staticdata[y+3-i]==0xff){
  305.                         for(j=y+3-i;j>0;j--){
  306.                                 staticdata[j]=staticdata[j-1];
  307.                         }
  308.                         i--,r--;
  309.                 }
  310.         }
  311.         return 4-r;                                                        //函数返回一次性消掉的行的数目
  312. }
  313. /****************************************************************************************/
  314. void startimage()                                                  //开机欢迎画面,在没有按键作用的时候会不断执行
  315. {
  316.         uchar i,j;
  317.         startcontrol=1;
  318.         while(startcontrol){
  319.                 for(i=10;i>0;i--){
  320.                         for(j=0;j<16;j+=2){
  321.                                 slock=1;P1=j;P3=0xaa;
  322.                                 slock=0;delayms(1);P3=0x00;
  323.                         }
  324.                         for(j=1;j<16;j+=2){
  325.                                 slock=1;P1=j;P3=0x55;
  326.                                 slock=0;delayms(1);P3=0x00;
  327.                         }
  328.                         keyscan();                                           //随时响应用户输入
  329.                 }               
  330.                 for(i=10;i>0;i--){
  331.                         for(j=1;j<16;j+=2){
  332.                                 slock=1;P1=j;P3=0xaa;
  333.                                 slock=0;delayms(1);P3=0x00;
  334.                         }
  335.                         for(j=0;j<16;j+=2){
  336.                                 slock=1;P1=j;P3=0x55;
  337.                                 slock=0;delayms(1);P3=0x00;
  338.                         }
  339.                         keyscan();                                        //随时响应用户输入       
  340.                 }
  341.         }
  342. }
  343. /****************************************************************************************/
  344. void overimage()                                                  //游戏结束画面,分数会强制闪烁8次,并自动结束
  345. {
  346.         int i,j;
  347.         for(j=0;j<8;j++){
  348.                 for(i=0;i<200;i++){
  349.                         numberdisplay(mark);       
  350.                 }
  351.                 delayms(500);
  352.         }
  353. }       
  354. /****************************************************************************************/
  355. void dataset()                                                           //数据全部清零,重新开始游戏
  356. {
  357.         char j;
  358.         y=0;
  359.         left=0;
  360.         shapenum=0;
  361.         initialspeed=100;
  362.         speed=initialspeed;
  363.         systemspeed=initialspeed;
  364.         fastspeed=5;
  365.         randnum=rand()%19;
  366.         shapenum=randnum;
  367.         mark=0;
  368.         for(j=0;j<19;j++){                                          //清除点阵上的显示数据
  369.                 staticdata[j]=0;
  370.         }
  371. }
  372. /****************************************************************************************/
复制代码
回复

使用道具 举报

ID:142493 发表于 2016-10-12 21:17 | 显示全部楼层
牛掰
回复

使用道具 举报

ID:208443 发表于 2017-7-25 08:17 | 显示全部楼层
强!~ 按照楼主做一个试试
回复

使用道具 举报

ID:236898 发表于 2017-10-4 19:35 | 显示全部楼层
谢谢大佬,国庆花几天做着玩一下
回复

使用道具 举报

ID:255861 发表于 2017-12-15 13:06 来自手机 | 显示全部楼层
我感觉非常有意思,而且内容给的非常的详细,程序很多注释,我这种小白都基本都能看懂,我单片机课程设计,就准备做它了,我准备先仿真一下试试看看
回复

使用道具 举报

ID:255861 发表于 2017-12-15 21:48 来自手机 | 显示全部楼层
太棒了!刚才试了一下,完全没有毛病,完美通过!看来我单片机课设,有着落啦!这就买东西!上一波图!
-39b1b04f5c4cef5e.png
-38941ed1ea78880.png
-159eee8cdf015562.png
-77f8a2a99b71463c.png
回复

使用道具 举报

ID:242133 发表于 2017-12-20 21:45 | 显示全部楼层
厉害啊
回复

使用道具 举报

ID:262061 发表于 2017-12-30 21:49 | 显示全部楼层
大大,我想问问为什么仿真的时候RESET复位无效呢
回复

使用道具 举报

ID:262061 发表于 2018-1-1 12:26 | 显示全部楼层
真滴有点帅哦 发表于 2017-12-15 21:48
太棒了!刚才试了一下,完全没有毛病,完美通过!看来我单片机课设,有着落啦!这就买东西!上一波图!

大大,我想问问为什么仿真的时候RESET复位无效呢
回复

使用道具 举报

ID:273035 发表于 2018-1-8 11:14 | 显示全部楼层
在实现过程中io设定还是有点问题
继续琢磨看看!
回复

使用道具 举报

ID:273035 发表于 2018-1-8 17:19 来自手机 | 显示全部楼层
想问pcb封装时 点阵引脚间距设定问题求助555
回复

使用道具 举报

ID:345426 发表于 2018-6-16 14:38 | 显示全部楼层
上传一个点阵引脚图
2345截图20180616143726.png

评分

参与人数 1黑币 +40 收起 理由
admin + 40 回帖助人的奖励!

查看全部评分

回复

使用道具 举报

ID:365277 发表于 2018-7-6 19:42 | 显示全部楼层
http://www.51hei.com/bbs/dpj-126816-1.html
大佬你好,我照着您的教程还原俄罗斯方块,通电后是这个状况,请问是什么原因?
想联系您aienn7086@gmail.com,看到能否回我!
回复

使用道具 举报

ID:659095 发表于 2019-12-9 09:14 | 显示全部楼层
楼主可以帮我看一下是怎么回事吗
俄罗斯方块.png
回复

使用道具 举报

ID:225288 发表于 2020-1-2 23:43 | 显示全部楼层
很有参考价值
回复

使用道具 举报

ID:283883 发表于 2020-1-4 08:07 | 显示全部楼层
黑币不够啊,能不能把这么多文件放在一个压缩包里,谢谢!
回复

使用道具 举报

ID:845639 发表于 2020-12-16 20:27 | 显示全部楼层
很不错,对于初学者有很大的帮助
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表