找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2576|回复: 0
打印 上一主题 下一主题
收起左侧

单片机俄罗斯方块游戏Proteus仿真程序

[复制链接]
跳转到指定楼层
楼主
俄罗斯方块仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)


单片机源程序如下:
  1. //描 述:                                                                   //
  2. //      1、功能完整,直接使用                                               //
  3. //      2、模块独立性强,移植方便,外部仅init和move函数,修改显示和输入即可 //
  4. //      3、对减少内存占用、尽量减少屏幕操作进行适当优化                     //
  5. //      4、新方块生成高度随机,绝对无规律                                   //
  6. //      5、仿真环境为Keil7.5+Proteus6.5,可以联机也可脱机运行                //
  7. //      CODE SIZE        =   1845    ----                                   //
  8. //      CONSTANT SIZE    =    326    ----                                   //
  9. //      DATA SIZE        =     16      19                                   //
  10. //      IDATA SIZE       =     50    ----                                   //
  11. //      BIT SIZE         =      1       1                                   //
  12. //--------------------------------------------------------------------------//
  13. #include <stdlib.h>
  14. #include "xwj_lcd16.h"                                 // 字符液晶控制函数声明    //
  15. #include "xwj_lcd6963.h"                        // T6963C 公用函数
  16. #include "xwj_hlkey.h"                                //  P1口行列式键盘  //
  17. #include "xwj_serial.h"                                //串口函数集
  18. #include "change.h"                                        //数制转换
  19. #include "xwj_fk.h"                                        //俄罗斯方块程序

  20. #define ulong                unsigned long
  21. #define uint                unsigned int
  22. #define uchar                unsigned char

  23. extern void delay(unsigned int x);
  24. //----------------俄罗斯方块内部函数----------------------------------------//
  25. void fk_dot(uchar x,uchar y);                //显示1个方块点
  26. void fk_cldot(uchar x,uchar y);                //清除1个方块点
  27. void fk_show(void);                                        //显示分数
  28. void fk_reffk(void);                                //刷新方块
  29. void fk_refnew(void);                                //刷新预览方块
  30. void fk_refline(yy);                                //刷新1行背景
  31. bit  fk_chk(void);                                        //冲突检查
  32. void fk_new(void);                                        //产生新方块
  33. void fk_add(void);                                        //方块合并

  34. /*
  35. //-----------------俄罗斯方块公用函数--------------------------------------//
  36. void fk_init(void);                                                //方块初始化
  37. void fk_move(unsigned char mode);                //移动方块
  38. */

  39. //-------------------------------------------------------------------------//
  40. #define FULLMAP        0x0fff                                /*掩码*/
  41. #define LINEGUAN        20                                /*20行过一关*/
  42. #define NEWX        15                                        /*预览方块X位置*/
  43. #define NEWY        12                                        /*预览方块Y位置*/
  44. #define LINEMAX        21                                        /*屏幕最高21行*/
  45. uint idata fk_map[LINEMAX+4];                //背景映象
  46. uchar  fk_x,fk_y,fk_r;                                //方块左右、高度、方向
  47. uchar fk_type;                                                //方块形状
  48. uchar  fk_oldx,fk_oldy,fk_oldr;                //方块上次左右、高度、方向
  49. uchar  fk_newtype,fk_newr;                        //新方块形状、方向
  50. uint score;                                                        //总分
  51. uint line;                                                        //总行数        
  52. uchar speed;                                                //速度
  53. uchar moven;                                                //速度相关计数器
  54. uchar automapn;                                                //随机方块的行数
  55. bit fk_run;                                                        //俄罗斯方坑蜗吩诵?
  56.         
  57. uchar code fk_mod[][4][4]={                        //方块模型号,4个方向,4行
  58.         0,0,7,2,0,1,3,1,0,0,2,7,0,2,3,2,        //_|_
  59.         0,0,6,3,0,1,3,2,0,0,6,3,0,1,3,2,        //_|~
  60.         0,0,3,6,0,2,3,1,0,0,3,6,0,2,3,1,        //~|_
  61.         0,0,7,4,0,3,1,1,0,0,1,7,0,2,2,3,        //|__
  62.         0,0,7,1,0,1,1,3,0,0,4,7,0,3,2,2,        //__|
  63.         0,0,0,15,1,1,1,1,0,0,0,15,1,1,1,1,        //____
  64.         0,0,3,3,0,0,3,3,0,0,3,3,0,0,3,3,        //田字
  65. };

  66. uchar code strmap[4][9]={
  67.         "不错!  ","真棒!  ","好极啦!","太棒了!",
  68. };

  69. //--------------------------------------------------------------------------//
  70. void fk_dot(uchar x,uchar y)                //显示1个方块点
  71. {
  72.         printat(x*3+1, 241-(y-4)*12,"■");
  73. }

  74. //--------------------------------------------------------------------------//
  75. void fk_cldot(uchar x,uchar y)                //清除1个方块点
  76. {
  77. //        printat(x*3+1, 241-(y-4)*12,"□");
  78.         printat(x*3+1, 241-(y-4)*12,"┘");
  79. }

  80. //--------------------------------------------------------------------------//
  81. void fk_show(void)                                        //显示分数
  82. {
  83.         printat(50, 12,chnint(score,1));
  84.         printat(60, 12,"00");
  85.         printat(40, 12,"得分:");
  86.         printat(54,36,chnint(line,1));
  87.         printat(40, 36,"行数:");
  88.         printat(54,60,chnchar(speed,1));
  89.         printat(40,60,"速度:");
  90.         printat(54,84,chnchar(automapn,1));
  91.         printat(40,84,"关数:");               
  92. }

  93. //--------------------------------------------------------------------------//
  94. void fk_reffk(void)                                        //刷新方块
  95. {
  96.         uchar i,j;
  97.         uchar temp;
  98.         //----------------------------------------------//清除原来的方块
  99.         for (i=0;i<4;i++)
  100.         {
  101.                 temp=(fk_mod[fk_type][fk_oldr][i]);
  102.                 for (j=fk_oldx;j<fk_oldx+4;j++)
  103.                 {
  104.                         if(temp&0x01)
  105.                         {
  106.                                 fk_cldot(j,fk_oldy+i);
  107.                         }
  108.                         temp>>=1;
  109.                 }
  110.         }
  111.         //----------------------------------------------//显示新的方块
  112.         for (i=0;i<4;i++)
  113.         {
  114.                 temp=(fk_mod[fk_type][fk_r][i]);
  115.                 for (j=fk_x;j<fk_x+4;j++)
  116.                 {
  117.                         if(temp&0x01)
  118.                         {
  119.                                 fk_dot(j,fk_y+i);
  120.                         }
  121.                         temp>>=1;
  122.                 }
  123.         }
  124.         fk_oldx=fk_x;fk_oldy=fk_y;fk_oldr=fk_r;        //保存新方块位置
  125. }

  126. //--------------------------------------------------------------------------//
  127. void fk_refnew(void)                                //刷新预览方块
  128. {
  129.         uchar i,j;
  130.         uchar temp;
  131.         //----------------------------------------------//预览方块
  132.         for (i=0;i<4;i++)
  133.         {
  134.                 temp=(fk_mod[fk_newtype][fk_newr][i]);
  135.                 for (j=NEWX;j<NEWX+4;j++)
  136.                 {
  137.                         if(temp&0x01)
  138.                         {
  139.                                 fk_dot(j,NEWY+i);
  140.                         }
  141.                         else
  142.                         {
  143.                                 fk_cldot(j,NEWY+i);
  144.                         }
  145.                         temp>>=1;
  146.                 }
  147.         }
  148. }

  149. //--------------------------------------------------------------------------//
  150. void fk_refline(yy)                                        //刷新1行背景
  151. {
  152.         uchar i;
  153.         uint temp;
  154.         if (yy>=4)
  155.         {
  156.                 temp=fk_map[yy];
  157.                 for (i=0;i<12;i++)
  158.                 {
  159.                         if ((temp&0x01) !=0)
  160.                                 fk_dot(i,yy);
  161.                         else
  162.                                 fk_cldot(i,yy);
  163.                         temp >>= 1;
  164.                 }
  165.         }
  166. }

  167. //--------------------------------------------------------------------------//
  168. bit fk_chk(void)                                        //冲突检查
  169. {
  170.         uchar i;
  171.         bit neq=0;
  172.         for (i=0;i<4;i++)
  173.         {
  174.                 if ( (((fk_mod[fk_type][fk_r][i])<<fk_x)+(fk_map[fk_y+i])) != (((fk_mod[fk_type][fk_r][i])<<fk_x)|(fk_map[fk_y+i])) )
  175.                         neq=1;
  176.         }
  177.         return(neq);
  178. }

  179. //--------------------------------------------------------------------------//
  180. void fk_new(void)                                                //产生新方块
  181. {
  182.         srand(rand()+fk_x+fk_y+fk_r);
  183.         fk_oldx=fk_x=5;
  184.         fk_oldy=fk_y=LINEMAX;
  185.     fk_type = fk_newtype;
  186.         fk_oldr=fk_newr;
  187.     fk_newtype = rand()%7;
  188.         fk_newr=rand()%4;
  189.         fk_refnew();                        //刷新预览方块
  190.         if (fk_run)
  191.                 fk_reffk();        //刷新显示
  192. }

  193. //--------------------------------------------------------------------------//
  194. void fk_add(void)                                        //方块合并
  195. {
  196.         uchar i,j;
  197.         uchar full=0x00;
  198.         uchar fulltemp;
  199.         uchar fullline=0x00;
  200.         for (i=0;i<4;i++)        //方块合并
  201.         {
  202.                 fk_map[fk_y+i] |= (fk_mod[fk_type][fk_r][i])<<fk_x;
  203.                 full <<= 1;
  204.                 if ((fk_y+i >= 4) && (fk_map[fk_y+i] == 0xffff))                //满行
  205.                 {
  206.                         full |= 0x01;
  207.                 }
  208.         }
  209.         if (full != 0)                //有满行
  210.         {
  211.                 for (j=0;j<3;j++)                //消行闪烁3次
  212.                 {
  213.                         delay(300);
  214.                         fulltemp=full;
  215.                         for (i=0;i<4;i++)        //4行
  216.                         {
  217.                                 if ((fulltemp&0x08) != 0)
  218.                                 {
  219.                                         fk_map[fk_y+i] ^= FULLMAP;
  220.                                 }
  221.                                 fk_refline(fk_y+i);
  222.                                 fulltemp <<= 1;
  223.                         }
  224.                 }
  225.                 fulltemp=full;
  226.                 for (i=fk_y;i<LINEMAX+4+fullline;i++)        //上面行下移
  227.                 {
  228.                         if ((i < LINEMAX+4)&&(fk_map[i-fullline]!=fk_map[i]))
  229.                         {
  230.                                 fk_map[i-fullline]=fk_map[i];
  231.                                 fk_refline(i-fullline);
  232.                         }
  233.                         if ((i >= LINEMAX+4)&&(fk_map[i-fullline]!=~FULLMAP))
  234.                         {
  235.                                 fk_map[i-fullline]=~FULLMAP;        //背景映象
  236.                                 fk_refline(i-fullline);
  237.                         }
  238.                         if ((fulltemp&0x08) != 0)
  239.                         {
  240.                                 fullline++;
  241.                         }
  242.                         fulltemp <<= 1;
  243.                 }
  244.                 if (((line+fullline)/LINEGUAN) != (line/LINEGUAN))//每20行速度+1
  245.                         speed ++;
  246.                 line += fullline;                                //更新分数、行数
  247.                 score += (1<<fullline)-1;
  248.                 printat(46,180,strmap[fullline-1]);        //夸奖
  249.                 fk_show();                                                //显示分数
  250.                 fk_new();                        //产生新方块
  251.         }
  252.         else
  253.         {
  254.                 if (fk_y > LINEMAX-10)        //在最高位置碰撞且不能消行则游戏结束
  255.                         printat(46,180,"加油啊!");                //加油啊
  256.                 if (fk_y > LINEMAX-6)        //在最高位置碰撞且不能消行则游戏结束
  257.                         printat(46,180,"糟糕了!");                //糟糕了

  258.                 if (fk_y==LINEMAX)                //在最高位置碰撞且不能消行则游戏结束
  259.                         fk_run=0;        //方块初始化
  260.                 else
  261.                         fk_new();        //产生新方块
  262.         }
  263. }

  264. //--------------------------------------------------------------------------//
  265. void fk_init(void)                                        //方块初始化
  266. {
  267.         uchar i;
  268.         fk_run = 0;
  269.         moven=0;
  270.         Lcd6963Cls();
  271.         Lcd6963Rec(0,0,152,255);
  272.         Lcd6963ChHz(0);                                        //切换到16X16点阵
  273.         printat(2, 16,"欢迎光临文君阁");
  274.         printat(2, 48,"请按键选择:");
  275.         printat(2, 80,"-----------------");
  276.         printat(2, 96,"7左旋 8右旋 9右旋");
  277.         printat(2, 112,"4左移 5右旋 6右移");
  278.         printat(2, 128,"4速度 5开始 6关数");
  279.         printat(2, 144,"1左移 2下移 3右移");
  280.         printat(2, 160,"-----------------");
  281.         Lcd6963ChHz(1);                                        //切换到12X12点阵
  282.         printat(46,180,"欢迎使用");
  283.         fk_show();                                                //显示分数
  284.         while (~fk_run)
  285.         {
  286.                 fk_move();                                        //等待设置速度关数开始
  287.                 delay(10);
  288.         }
  289.         for (i=0;i<4;i++)
  290.         {
  291.                 fk_map[i]=0xffff;        //背景映象
  292.         }        delay(3000);
  293.         for (i=4;i<LINEMAX+4;i++)
  294.         {
  295.                 if (i<(automapn+4))
  296.                         fk_map[i]=rand()-1|~FULLMAP; //背景映象
  297.                 else
  298.                         fk_map[i]=~FULLMAP;                //背景映象
  299.                 fk_refline(i);                                //刷新1行背景
  300.         }
  301.         fk_show();                                                //显示分数
  302. //        fk_new();                                                //产生新方块
  303. }   

  304. //--------------------------------------------------------------------------//
  305. void fk_move(void)                                                //移动方块
  306. {
  307.         unsigned char temp;
  308.         if(KeyTest())                                        //检查有无按键
  309.         {
  310.                 putinbuf(KeyGetCode());                //按键码输入接收缓冲区
  311.         }
  312.         if (checkin())
  313.         {
  314.                 temp=getbyte();
  315.                 if (temp!=0) Lcd16WrCharhh(12,0,temp);
  316.                 if (temp!=0) Lcd16WrChar(15,0,temp);
  317.                 putchar(temp);
  318.         }
  319.         else
  320.                 temp=0xff;                                        //无键设为无效键用于下移方块
  321.         temp -= '0';
  322.         switch(temp)
  323.         {
  324.         default:
  325.                 if (--moven)                                //游戏难度
  326.                         break;
  327.                 else
  328.                 {
  329.                         moven=(252>>speed)+2;
  330.                 }
  331.         case 2:                //下移
  332.                 if (fk_run)                                        //游戏中下移
  333.                 {
  334.                         if(fk_y>0)
  335.                         {
  336.                                 fk_y--;
  337.                                 if(fk_chk())
  338.                                 {
  339.                                         fk_y++;                //有冲突取消操作,执行碰撞组合
  340.                                         fk_add();        //方块合并        //产生新方块
  341.                                 }
  342.                         }
  343.                         else                                //方块到底也执行碰撞组合
  344.                         {
  345.                                 fk_add();                //方块合并
  346.                         }
  347.                 }
  348.                 else                                                //初始化时
  349.                 {
  350.                         fk_new();                                //产生新方块
  351.                 }
  352.                 break;
  353.         case 0:                //下移到底
  354.                 while((fk_y>0)&&~(fk_chk())) //一直下移直到冲突
  355.                 {
  356.                         fk_y--;
  357.                 }
  358.                 moven=1;
  359.                 fk_y++;                                //恢复到未冲突位置
  360.                 break;
  361.         case 3:                //右移
  362.         case 6:                //右移
  363.                 if (fk_run)                                        //游戏中右移
  364.                 {
  365.                         if(fk_x<12)
  366.                         {
  367.                                 fk_x++;
  368.                                 if(fk_chk())
  369.                                         fk_x--;//有冲突取消操作
  370.                         }
  371.                 }
  372.                 else                                                        //初始化时
  373.                 {
  374.                         automapn++;
  375.                         automapn &= 0x0f;
  376.                         fk_show();                                        //显示分数
  377.                 }
  378.                 break;
  379.         case 1:                //左移
  380.         case 4:                //移
  381.                 if (fk_run)                                                //游戏中左移
  382.                 {
  383.                         if(fk_x>0)
  384.                         {
  385.                                 fk_x--;
  386.                                 if(fk_chk())
  387.                                         fk_x++;//有冲突取消操作
  388.                         }
  389.                 }
  390.                 else                                                        //初始化时
  391.                 {
  392.                         speed++;
  393.                         speed &= 0x07;
  394.                         fk_show();                                        //显示分数
  395.                 }
  396.                 break;
  397.         case 9:                //右转
  398.         case 8:                //右转
  399.         case 5:                //右转
  400.                 if (fk_run)                                                //游戏中右转
  401.                 {
  402.                         fk_r++;
  403.                         if(fk_chk())
  404.                                 fk_r--;                                        //有冲突取消操作
  405.                         fk_r &= 0x03;
  406.                 }
  407.                 else                                                        //初始化时
  408.                 {
  409.                         fk_run = 1;
  410.                 }
  411.                 break;
  412.         case 7:                //左转
  413.                 if (fk_run)                                                //游戏中右转
  414.                 {
  415.                         fk_r--;
  416.                         if(fk_chk())
  417.                                 fk_r++;                                //有冲突取消操作
  418.                         fk_r &= 0x03;
  419.                 }
  420.                 else                                                        //初始化时
  421.                 {
  422.                         fk_run = 1;
  423.                 }
  424.                 break;
  425.         }
  426.         if((fk_run)&& ((fk_x!=fk_oldx)||(fk_y!=fk_oldy)||(fk_r!=fk_oldr)) )
  427.         {
  428.                 fk_reffk();        //刷新显示
  429.         }
  430.         rand();
  431. }

  432. /*
  433. // ---------------------------------------------- //        32字节
  434. void delay(uint x)
  435. {
  436.    uint i,j;
  437.    for (i=0; i<x;i++) {
  438.       for (j=0;j<102; j++) ;
  439.    }
  440. }

  441. //--------------------------------------------------------------------------//
  442. void main(void)                                                // 测试用
  443. {
  444.         serial_init();
  445.         Lcd6963Init();                                        //Lcd6963复位
  446.         Lcd16Reset();                                        //Lcd16复位
  447.         Serial_main();                                        //        串口测试用主函数  
  448.         Lcd16main();                                        //Lcd16临时测试主程序
  449.         Lcd6963main();                                        //Lcd6963测试用
  450.         fk_init();                                                //方块初始化
  451.         while(1)
  452.         {
  453.                 if (~fk_run)
  454.                         fk_init();                                                //方块初始化
  455.                 fk_move();                                        //移动方块
  456.                 delay(10);
  457.         }
  458. }
  459. */
复制代码

全部资料51hei下载地址:
20项目二十 俄罗斯方块游戏.7z (312.71 KB, 下载次数: 28)

评分

参与人数 1黑币 +50 收起 理由
admin + 50 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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