找回密码
 立即注册

QQ登录

只需一步,快速开始

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

虚拟串口控制的俄罗斯方块游戏仿真及源码

[复制链接]
跳转到指定楼层
楼主
今天给51黑电子论坛的坛友共享一个好东东,使用51单片机实现的俄罗斯方块游戏, 能虚拟串口控制,实用性还是比较高的,下面是仿真原理图,大家可以下载附件后直接用proteus打开。


所有资料包含仿真工程文件和源码下载:
俄罗斯方块游戏.rar (422.54 KB, 下载次数: 14)


俄罗斯方块源程序:
  1. //--------------------------------------------------------------------------//
  2. //                                源程序大公开                              //
  3. //                    (c) Copyright 2001-2025 xuwenjun                     //
  4. //                            All Rights Reserved                           //
  5. //                                    V1.00                                 //
  6. //--------------------------------------------------------------------------//
  7. //标 题: 俄罗斯方块程序                            ?                      //
  8. //文件名: xwj_fk.c                                                          //
  9. //版 本: V1.00                                                             //
  10. //修改人: 徐文军                         E-mail:xuwenjun@21cn.com           //
  11. //日 期: 05-13                                                           //
  12. //描 述: 俄罗斯方块程序                            ?                      //
  13. //声 明:                                                                   //
  14. //        以下代码仅免费提供给学习用途,但引用或修改后必须在文件中声明出处. //
  15. //        如用于商业用途请与作者联系.    E-mail:xuwenjun@21cn.com           //
  16. //        有问题请mailto xuwenjun@21cn.com   欢迎与我交流!                  //
  17. //--------------------------------------------------------------------------//
  18. //老版本: 无                             老版本文件名:                      //
  19. //创建人: 徐文军                         E-mail:xuwenjun@21cn.com           //
  20. //日 期: 05-13                                                          //
  21. //描 述:                                                                   //
  22. //      1、功能完整,直接使用                                               //
  23. //      2、模块独立性强,移植方便,外部仅init和move函数,修改显示和输入即可 //
  24. //      3、对减少内存占用、尽量减少屏幕操作进行适当优化                     //
  25. //      4、新方块生成高度随机,绝对无规律                                   //
  26. //      5、仿真环境为Keil7.5+Proteus6.5,可以联机也可脱机运行                //
  27. //      CODE SIZE        =   1845    ----                                   //
  28. //      CONSTANT SIZE    =    326    ----                                   //
  29. //      DATA SIZE        =     16      19                                   //
  30. //      IDATA SIZE       =     50    ----                                   //
  31. //      BIT SIZE         =      1       1                                   //
  32. //--------------------------------------------------------------------------//
  33. #include <stdlib.h>
  34. #include "xwj_lcd16.h"                                 // 字符液晶控制函数声明    //
  35. #include "xwj_lcd6963.h"                        // T6963C 公用函数
  36. #include "xwj_hlkey.h"                                //  P1口行列式键盘  //
  37. #include "xwj_serial.h"                                //串口函数集
  38. #include "change.h"                                        //数制转换
  39. #include "xwj_fk.h"                                        //俄罗斯方块程序

  40. #define ulong                unsigned long
  41. #define uint                unsigned int
  42. #define uchar                unsigned char

  43. extern void delay(unsigned int x);
  44. //----------------俄罗斯方块内部函数----------------------------------------//
  45. void fk_dot(uchar x,uchar y);                //显示1个方块点
  46. void fk_cldot(uchar x,uchar y);                //清除1个方块点
  47. void fk_show(void);                                        //显示分数
  48. void fk_reffk(void);                                //刷新方块
  49. void fk_refnew(void);                                //刷新预览方块
  50. void fk_refline(yy);                                //刷新1行背景
  51. bit  fk_chk(void);                                        //冲突检查
  52. void fk_new(void);                                        //产生新方块
  53. void fk_add(void);                                        //方块合并

  54. /*
  55. //-----------------俄罗斯方块公用函数--------------------------------------//
  56. void fk_init(void);                                                //方块初始化
  57. void fk_move(unsigned char mode);                //移动方块
  58. */

  59. //-------------------------------------------------------------------------//
  60. #define FULLMAP        0x0fff                                /*掩码*/
  61. #define LINEGUAN        20                                /*20行过一关*/
  62. #define NEWX        15                                        /*预览方块X位置*/
  63. #define NEWY        12                                        /*预览方块Y位置*/
  64. #define LINEMAX        21                                        /*屏幕最高21行*/
  65. uint idata fk_map[LINEMAX+4];                //背景映象
  66. uchar  fk_x,fk_y,fk_r;                                //方块左右、高度、方向
  67. uchar fk_type;                                                //方块形状
  68. uchar  fk_oldx,fk_oldy,fk_oldr;                //方块上次左右、高度、方向
  69. uchar  fk_newtype,fk_newr;                        //新方块形状、方向
  70. uint score;                                                        //总分
  71. uint line;                                                        //总行数        
  72. uchar speed;                                                //速度
  73. uchar moven;                                                //速度相关计数器
  74. uchar automapn;                                                //随机方块的行数
  75. bit fk_run;                                                        //俄罗斯方坑蜗吩诵?
  76.         
  77. uchar code fk_mod[][4][4]={                        //方块模型号,4个方向,4行
  78.         0,0,7,2,0,1,3,1,0,0,2,7,0,2,3,2,        //_|_
  79.         0,0,6,3,0,1,3,2,0,0,6,3,0,1,3,2,        //_|~
  80.         0,0,3,6,0,2,3,1,0,0,3,6,0,2,3,1,        //~|_
  81.         0,0,7,4,0,3,1,1,0,0,1,7,0,2,2,3,        //|__
  82.         0,0,7,1,0,1,1,3,0,0,4,7,0,3,2,2,        //__|
  83.         0,0,0,15,1,1,1,1,0,0,0,15,1,1,1,1,        //____
  84.         0,0,3,3,0,0,3,3,0,0,3,3,0,0,3,3,        //田字
  85. };

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

  89. //--------------------------------------------------------------------------//
  90. void fk_dot(uchar x,uchar y)                //显示1个方块点
  91. {
  92.         printat(x*3+1, 241-(y-4)*12,"■");
  93. }

  94. //--------------------------------------------------------------------------//
  95. void fk_cldot(uchar x,uchar y)                //清除1个方块点
  96. {
  97. //        printat(x*3+1, 241-(y-4)*12,"□");
  98.         printat(x*3+1, 241-(y-4)*12,"┘");
  99. }

  100. //--------------------------------------------------------------------------//
  101. void fk_show(void)                                        //显示分数
  102. {
  103.         printat(50, 12,chnint(score,1));
  104.         printat(60, 12,"00");
  105.         printat(40, 12,"得分:");
  106.         printat(54,36,chnint(line,1));
  107.         printat(40, 36,"行数:");
  108.         printat(54,60,chnchar(speed,1));
  109.         printat(40,60,"速度:");
  110.         printat(54,84,chnchar(automapn,1));
  111.         printat(40,84,"关数:");               
  112. }

  113. //--------------------------------------------------------------------------//
  114. void fk_reffk(void)                                        //刷新方块
  115. {
  116.         uchar i,j;
  117.         uchar temp;
  118.         //----------------------------------------------//清除原来的方块
  119.         for (i=0;i<4;i++)
  120.         {
  121.                 temp=(fk_mod[fk_type][fk_oldr][i]);
  122.                 for (j=fk_oldx;j<fk_oldx+4;j++)
  123.                 {
  124.                         if(temp&0x01)
  125.                         {
  126.                                 fk_cldot(j,fk_oldy+i);
  127.                         }
  128.                         temp>>=1;
  129.                 }
  130.         }
  131.         //----------------------------------------------//显示新的方块
  132.         for (i=0;i<4;i++)
  133.         {
  134.                 temp=(fk_mod[fk_type][fk_r][i]);
  135.                 for (j=fk_x;j<fk_x+4;j++)
  136.                 {
  137.                         if(temp&0x01)
  138.                         {
  139.                                 fk_dot(j,fk_y+i);
  140.                         }
  141.                         temp>>=1;
  142.                 }
  143.         }
  144.         fk_oldx=fk_x;fk_oldy=fk_y;fk_oldr=fk_r;        //保存新方块位置
  145. }

  146. //--------------------------------------------------------------------------//
  147. void fk_refnew(void)                                //刷新预览方块
  148. {
  149.         uchar i,j;
  150.         uchar temp;
  151.         //----------------------------------------------//预览方块
  152.         for (i=0;i<4;i++)
  153.         {
  154.                 temp=(fk_mod[fk_newtype][fk_newr][i]);
  155.                 for (j=NEWX;j<NEWX+4;j++)
  156.                 {
  157.                         if(temp&0x01)
  158.                         {
  159.                                 fk_dot(j,NEWY+i);
  160.                         }
  161.                         else
  162.                         {
  163.                                 fk_cldot(j,NEWY+i);
  164.                         }
  165.                         temp>>=1;
  166.                 }
  167.         }
  168. }

  169. //--------------------------------------------------------------------------//
  170. void fk_refline(yy)                                        //刷新1行背景
  171. {
  172.         uchar i;
  173.         uint temp;
  174.         if (yy>=4)
  175.         {
  176.                 temp=fk_map[yy];
  177.                 for (i=0;i<12;i++)
  178.                 {
  179.                         if ((temp&0x01) !=0)
  180.                                 fk_dot(i,yy);
  181.                         else
  182.                                 fk_cldot(i,yy);
  183.                         temp >>= 1;
  184.                 }
  185.         }
  186. }

  187. //--------------------------------------------------------------------------//
  188. bit fk_chk(void)                                        //冲突检查
  189. {
  190.         uchar i;
  191.         bit neq=0;
  192.         for (i=0;i<4;i++)
  193.         {
  194.                 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])) )
  195.                         neq=1;
  196.         }
  197.         return(neq);
  198. }

  199. //--------------------------------------------------------------------------//
  200. void fk_new(void)                                                //产生新方块
  201. {
  202.         srand(rand()+fk_x+fk_y+fk_r);
  203.         fk_oldx=fk_x=5;
  204.         fk_oldy=fk_y=LINEMAX;
  205.     fk_type = fk_newtype;
  206.         fk_oldr=fk_newr;
  207.     fk_newtype = rand()%7;
  208.         fk_newr=rand()%4;
  209.         fk_refnew();                        //刷新预览方块
  210.         if (fk_run)
  211.                 fk_reffk();        //刷新显示
  212. }

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

  278.                 if (fk_y==LINEMAX)                //在最高位置碰撞且不能消行则游戏结束
  279.                         fk_run=0;        //方块初始化
  280.                 else
  281.                         fk_new();        //产生新方块
  282.         }
  283. }

  284. //--------------------------------------------------------------------------//
  285. void fk_init(void)                                        //方块初始化
  286. {
  287.         uchar i;
  288.         fk_run = 0;
  289.         moven=0;
  290.         Lcd6963Cls();
  291.         Lcd6963Rec(0,0,152,255);
  292.         Lcd6963ChHz(0);                                        //切换到16X16点阵
  293.         printat(2, 16,"欢迎光临文君阁");
  294.         printat(2, 48,"请按键选择:");
  295.         printat(2, 80,"-----------------");
  296.         printat(2, 96,"7左旋 8右旋 9右旋");
  297.         printat(2, 112,"4左移 5右旋 6右移");
  298.         printat(2, 128,"4速度 5开始 6关数");
  299.         printat(2, 144,"1左移 2下移 3右移");
  300.         printat(2, 160,"-----------------");
  301.         Lcd6963ChHz(1);                                        //切换到12X12点阵
  302.         printat(46,180,"欢迎使用");
  303.         fk_show();                                                //显示分数
  304.         while (~fk_run)
  305.         {
  306.                 fk_move();                                        //等待设置速度关数开始
  307.                 delay(10);
  308.         }
  309.         for (i=0;i<4;i++)
  310.         {
  311.                 fk_map[i]=0xffff;        //背景映象
  312.         }        delay(3000);
  313.         for (i=4;i<LINEMAX+4;i++)
  314.         {
  315.                 if (i<(automapn+4))
  316.                         fk_map[i]=rand()-1|~FULLMAP; //背景映象
  317.                 else
  318.                         fk_map[i]=~FULLMAP;                //背景映象
  319.                 fk_refline(i);                                //刷新1行背景
  320.         }
  321.         fk_show();                                                //显示分数
  322. //        fk_new();                                                //产生新方块
  323. }   

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

  452. /*
  453. // ---------------------------------------------- //        32字节
  454. void delay(uint x)
  455. {
  456.    uint i,j;
  457.    for (i=0; i<x;i++) {
  458.       for (j=0;j<102; j++) ;
  459.    }
  460. }

  461. //--------------------------------------------------------------------------//
  462. void main(void)                                                // 测试用
  463. {
  464.         serial_init();
  465.         Lcd6963Init();                                        //Lcd6963复位
  466.         Lcd16Reset();                                        //Lcd16复位
  467.         Serial_main();                                        //        串口测试用主函数  
  468.         Lcd16main();                                        //Lcd16临时测试主程序
  469.         Lcd6963main();                                        //Lcd6963测试用
  470.         fk_init();                                                //方块初始化
  471.         while(1)
  472.         {
  473.                 if (~fk_run)
  474.                         fk_init();                                                //方块初始化
  475.                 fk_move();                                        //移动方块
  476.                 delay(10);
  477.         }
  478. }
  479. */
复制代码

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

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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