找回密码
 立即注册

QQ登录

只需一步,快速开始

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

16*16点阵弹弹球球小游戏制作,含单片机源代码(有注释)

[复制链接]
跳转到指定楼层
楼主
ID:335193 发表于 2018-6-1 15:19 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这是在师傅那里拿到点阵板后为了练习16*16点阵板写的一个弹球小游戏,算法是自己写的一、使用的工具
1.点阵板:七星虫德飞莱的LY-LED16*16BV2.1
2.单片机:STC89C52 LY51-L2c的单片机,晶振是12.000
3.编程软件:Keil
4.调试工具:stc-isp-15xx-v6.86D
5.STC的89c52 USB转串口线驱动

二,主要功能有下1.显示开始界面



2.消除,并数码管显示分数


3.继续消除


4.结束游戏


5.游戏中可以加速和减速小球
6.消除完全部小球后会显示笑脸

三、规则
开始、结束、胜利中使用s4作为确认键
开始游戏后按键功能如下
1.s1 左移
2.s2 右移
3.s3 减速
4.s4 加速

四、缺点
1.要消除完一整行之后才能消除下一行
2.挡板的和球的反弹有点问题
3.别的还有问题希望大家多多指教

五、单片机源程序如下:
  1. /*-----------------------------------------------
  2.   名称:弹弹球游戏
  3.   编写:田*
  4.   日期:2018年
  5.   内容:屏+5V连接电源5V
  6.                   GND接GND
  7.         P3.0-P3.3分别连接A、B、C、D,用于控制16行
  8.         SCK时钟连接P1.5
  9.         LATCH锁存连接P1.6
  10.         R1红色数据信号连接至P1.4
  11.         G1绿色数据信号连接至P3.4,如果单红色屏此信号无需连接
  12.         OE使能端接P1.1
  13. ------------------------------------------------*/
  14. #include<reg52.h>
  15. #include "scanKey.h"
  16. #include "scanNum.h"

  17. sbit T_STR = P1^6;       // 锁存引脚,屏上标识位STR
  18. sbit R1    = P1^4;       // 数据引脚,屏上标识R1
  19. sbit G1    = P3^4;       // 数据引脚,屏上标识G1        ·没有该灯光,可不用
  20. sbit T_CLK = P1^5;       // 时钟引脚,屏上标识位CLK
  21. sbit OE    = P1^1;       // 使能引脚,屏上标识EN/OE

  22. unsigned char DIS[]={0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};        //行数据
  23. unsigned char ledShow[][32]={0x00};                                                                // 显示挡板
  24. code dotDis[8] = {0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};                // 扭转顺序

  25. void input2Byte(unsigned char dataR1);                                                        // 写入数据
  26. void init_Timer1(void);                                                                                        // 初始化定时器
  27. void position(int pos);                                                                                        // 移动挡板位置
  28. void gameOver();                                                                                                // 游戏结束
  29. void gameWin();                                                                                                        // 游戏胜利
  30. bit isGameWin();                                                                                                // 判断游戏是否胜利

  31. void gameMenu();                                                                                                 // 游戏菜单
  32. void playGame();                                                                                                // 开始游戏

  33. /*
  34.         以下是挡板移动位置的十六进制
  35.         1111 1000 0000 0000        ledShow[28] = 0xF8 ledShow[29] = 0x00
  36.         0111 1100 0000 0000        ledShow[28] = 0x7C ledShow[29] = 0x00
  37.         0011 1110 0000 0000        ledShow[28] = 0x3E ledShow[29] = 0x00
  38.         0001 1111 0000 0000        ledShow[28] = 0x1F ledShow[29] = 0x00

  39.         0000 1111 1000 0000        ledShow[28] = 0x0F ledShow[29] = 0x80
  40.         0000 0111 1100 0000        ledShow[28] = 0x07 ledShow[29] = 0xC0
  41.         0000 0011 1110 0000        ledShow[28] = 0x03 ledShow[29] = 0xE0
  42.         0000 0001 1111 0000        ledShow[28] = 0x01 ledShow[29] = 0xF0

  43.         0000 0000 1111 1000        ledShow[28] = 0x00 ledShow[29] = 0xF8
  44.         0000 0000 0111 1100        ledShow[28] = 0x00 ledShow[29] = 0x7C
  45.         0000 0000 0011 1110        ledShow[28] = 0x00 ledShow[29] = 0x3E
  46.         0000 0000 0001 1111 ledShow[28] = 0x00 ledShow[29] = 0x1F
  47. */
  48. bit move = 0;                                                                                                        // 是否移动
  49. bit isUp = 1;                                                                                                         // 小球往上
  50. bit isDown = 0;                                                                                                        // 小球往下
  51. char rolIndex = 26;                                                                                                // 初始行位置
  52. char colIndex = 3;                                                                                                // 初始列位置
  53. char pos = 5;                                                                                                        // 挡板位置
  54. char sysFun = 0;                                                                                                // 系统功能                                       
  55. bit gameState = 0;                                                                                                // 游戏状态
  56. char speed = 50;                                                                                                // 游戏速度
  57. unsigned short gameScore = 0;                                                                        // 游戏分数
  58. bit f_num = 0;                                                                                                        // 数码管显示

  59. // 主程序
  60. int main()
  61. {
  62.         static unsigned char count = 0;                                                                // 数码管显示计时
  63.         init_Timer1();                                                                                                 // 初始化定时器
  64.         fillDisBuf(gameScore,1);                                                                        // 填充数码管

  65.         while(1)
  66.         {
  67.                 scanKey();                                                                                                // 实时扫描按键        
  68.                 if (sysFun == 1 && f_num) {
  69.                         
  70.                         count++;
  71.                         if (count == 20) {                                                                         // 100ms比较好
  72.                            display();
  73.                            count = 0;
  74.                         }
  75.                         f_num = 0;
  76.                 }
  77.                
  78.                 /* 多任务控制核心 */
  79.                 switch(sysFun) {
  80.                         case 0:                                                                                                // 显示游戏菜单
  81.                                 gameMenu();
  82.                                 break;
  83.                         case 1:                                                                                                // 开始游戏
  84.                                  playGame();
  85.                                  break;
  86.                         case 2:                                                                                                // 游戏胜利
  87.                                 gameWin();
  88.                                 break;
  89.                         case 3:                                                                                                // 游戏结束
  90.                                 gameOver();
  91.                                 break;
  92.                 }
  93.         }
  94. }

  95. /* 显示游戏菜单 */
  96. void gameMenu() {
  97.         char i;
  98.         if (!gameState) {
  99.                
  100.                 // 全部先初始化为不亮
  101.                 for (i = 0; i < 32; i++){
  102.                         ledShow[0][i] = 0x00;
  103.                 }
  104.         
  105.                 // 初始化游戏LED灯,显示初始界面
  106.                 ledShow[0][0]  = 0xEA; ledShow[0][1]  = 0x05;
  107.                 ledShow[0][2]  = 0x2E; ledShow[0][3]  = 0xEF;
  108.                 ledShow[0][4]  = 0xEA; ledShow[0][5]  = 0x44;
  109.                 ledShow[0][6]  = 0x8E; ledShow[0][7]  = 0x4E;
  110.                 ledShow[0][8]  = 0xEA; ledShow[0][9]  = 0xF5;
  111.                 ledShow[0][10] = 0x2E; ledShow[0][11] = 0x44;
  112.                 ledShow[0][12] = 0x24; ledShow[0][13] = 0x4C;
  113.                 ledShow[0][14] = 0xEE; ledShow[0][15] = 0xE4;
  114.                 ledShow[0][16] = 0x04;

  115.                 gameState = 1;                                                                                        // 开启游戏状态为

  116.                 /* 挡板归位 */
  117.                 pos = 5;                                                                                                // 挡板初始位置
  118.                 rolIndex = 26;                                                                                        // 小球索引
  119.                 ledShow[0][rolIndex] = 0x01;                                                        // 球初始位置
  120.                 position(pos);                                                                                        // 显示挡板
  121.                 gameScore = 0;                                                                                        // 游戏归0
  122.         }

  123.         /* s4作为游戏开始 */
  124.         if (s4d) {
  125.                 s4d = 0;
  126.                 sysFun = 1;
  127.                 gameState = 1;
  128.         }
  129. }

  130. /* 玩游戏 */
  131. void playGame() {
  132.         char i;
  133.         if (gameState) {                                                                                         // 是否经过了初始化

  134.                 /* 初始化游戏区域 */
  135.                 gameState = 0;
  136.                 for (i = 0; i < 32; i++){
  137.                         if (i <= 15) {
  138.                                 ledShow[0][i] = 0xFF;
  139.                         }
  140.                         else{
  141.                                 ledShow[0][i] = 0x00;
  142.                         }
  143.                 }

  144.                 /* 挡板归位 */
  145.                 pos = 5;                                                                        // 挡板位置
  146.                 rolIndex = 26;                                                                // 小球索引
  147.                 ledShow[0][rolIndex] = 0x01;                                // 球初始位置
  148.                 position(pos);                                                                // 显示挡板
  149.                 gameScore = 0;                                                                // 游戏归0               
  150.         }
  151.          /* 根据按键移动挡板        */
  152.          if (s1d){
  153.                 s1d = 0;
  154.                 pos--;
  155.                 if (pos < 0) {                                                                 // 判断是否在边界,是则不能移动
  156.                         pos = 0;
  157.                 }
  158.                 else{
  159.                          position(pos);
  160.                 }

  161.                 /* 判断是否在另外一个区域的边界        */
  162.                 if (ledShow[0][rolIndex] == 0x80 && rolIndex == 27) {
  163.                      ledShow[0][rolIndex] = 0x00;                        // 关闭当前行
  164.                          rolIndex--;                                                         // 跳转下一行
  165.                          ledShow[0][rolIndex] = 0x01;                        // 新位置
  166.                 }
  167.                 else if (rolIndex >= 25 && rolIndex <= rolIndex + 2) {
  168.                         /* 判断是否在可移动边界 */
  169.                         if (ledShow[0][rolIndex] != 0x80) {                // 是否还能移动
  170.                                  ledShow[0][rolIndex] <<= 1;                        // 小球左移
  171.                         }
  172.                 }
  173.         }
  174.         if (s2d){
  175.                 s2d = 0;
  176.                 pos++;
  177.                 if (pos >= 12) {                                                         // 12是到右边界移动的距离
  178.                         pos = 11;
  179.                 }
  180.                 else{
  181.                          position(pos);                                                         // 往右移动挡板
  182.                 }

  183.                 /* 判断是否在另外一个区域的边界 */
  184.                 if (ledShow[0][rolIndex] == 0x01 && rolIndex == 26) {
  185.                      ledShow[0][rolIndex] = 0x00;
  186.                          rolIndex++;
  187.                          ledShow[0][rolIndex] = 0x80;
  188.                 }
  189.                 else if (rolIndex >= 25 && rolIndex <= rolIndex + 2) {

  190.                         /* 判断是否在可移动边界 */
  191.                         if (ledShow[0][rolIndex] != 0x01) {                // 判断是否已到达边界
  192.                                 ledShow[0][rolIndex] >>= 1;
  193.                         }
  194.                 }
  195.         }

  196.         // 游戏减速
  197.         if(s3d) {
  198.                 s3d = 0;

  199.                 // 加大延迟
  200.                 speed += 10;
  201.                 speed = (speed <= 50) ? speed : 50;
  202.         }
  203.         
  204.         // 游戏加速
  205.         if(s4d) {
  206.                 s4d = 0;

  207.                 // 减小延迟
  208.                 speed -= 10;
  209.                 speed = (speed >= 20) ? speed : 20;
  210.         }  
  211.         
  212.         // 点移动
  213.         if (move) {
  214.                 move = 0;
  215.                
  216.                 /* 当球往上移动的时候 */
  217.                 if (isUp) {
  218.                         rolIndex -= 2;                                                        // 点阵版是顺序加,-2才上球的正上方

  219.                         /* 如果是在空白区域则直接往上移动 */
  220.                         if (ledShow[0][rolIndex] == 0x00 && rolIndex > 0) {
  221.                                 ledShow[0][rolIndex] = ledShow[0][rolIndex+2];
  222.                                 ledShow[0][rolIndex+2] = 0x00;                // 移动之后需要将前一行灯关闭               
  223.                         }
  224.                         else if (rolIndex < 0) {                                // 判断是否到达边界
  225.                                 if(isGameWin()){                                        // 判断是否全部打完
  226.                                    sysFun = 2;                                                // 切换系统状态
  227.                                 }
  228.                                 else{
  229.                                         isUp = 0;
  230.                                            isDown = 1;
  231.                                            rolIndex += 2;                                         // +2回到顶部
  232.                                 }
  233.                         }
  234.                         else if (ledShow[0][rolIndex] != 0x00 &&
  235.                                 (ledShow[0][rolIndex] & ledShow[0][rolIndex+2]) == 0x00){
  236.                                 // 上一行没有消除完整但是正上一个为空,直接返回
  237.                                 
  238.                                 isUp = 0;
  239.                                    isDown = 1;
  240.                                    rolIndex += 2;                                       
  241.                         }        
  242.                         else if (ledShow[0][rolIndex] == 0xFF ||
  243.                                 (ledShow[0][rolIndex] & ledShow[0][rolIndex+2]) != 0x00) {
  244.                            
  245.                            // 判断上面一行是不是整行未消除或者正上方有
  246.                            ledShow[0][rolIndex] &= (~ledShow[0][rolIndex+2]);
  247.                            isUp = 0;
  248.                            isDown = 1;
  249.                            rolIndex += 2;

  250.                            // 根据小球速度进行加分
  251.                            switch(speed) {
  252.                                             case 50: gameScore += 1; break;                        // 四等级+1分
  253.                                         case 40: gameScore += 2; break;                           // 三等级+2分
  254.                                         case 30: gameScore += 3; break;                        // 二等级+3分
  255.                                         case 20: gameScore += 4; break;                        // 一等级+4分
  256.                            }
  257.                            fillDisBuf(gameScore,1);                                                // 分数+完填充数码管
  258.                         }
  259.                 }
  260.                    if (isDown) {
  261.                         rolIndex += 2;

  262.                         if (rolIndex > 31) {                                                        // 超出边界
  263.                                 rolIndex = 30;
  264.                                 sysFun = 3;                                                                        // 切换系统状态到结束
  265.                                 
  266.                         }
  267.                         else if (ledShow[0][rolIndex] == 0x00) {                // 空白区域直接下移
  268.                                 ledShow[0][rolIndex] = ledShow[0][rolIndex-2];
  269.                                 ledShow[0][rolIndex-2] = 0x00;        
  270.                         }
  271.                         else if ((ledShow[0][rolIndex]) != 0x00) {                // 碰到板
  272.                                 isUp = 1;
  273.                                    isDown = 0;
  274.                                 rolIndex -= 2;
  275.                         }
  276.                 }
  277.         }
  278. }

  279. /* 判断游戏胜利 */
  280. bit isGameWin() {
  281.         bit flag = 1;
  282.         char i;
  283.         for(i = 0; i < 16; i++) {                                                                // 上方砖块区域
  284.                 /*判断是否除了小球外游戏区域的砖块全部消除*/
  285.            if (ledShow[0][i] != 0x00 && ledShow[0][i] != ledShow[0][rolIndex+2]) {                                                        // 判断点阵是否全灭
  286.                            flag = 0;
  287.                         break;
  288.            }
  289.         }
  290.         return flag;
  291. }

  292. /* 游戏胜利 */
  293. void gameWin() {

  294.         // 游戏胜利标志
  295.         ledShow[0][0]  = 0x00; ledShow[0][1]  = 0x00;
  296.         ledShow[0][2]  = 0x00; ledShow[0][3]  = 0x00;
  297.         ledShow[0][4]  = 0x07; ledShow[0][5]  = 0xE0;
  298.         ledShow[0][6]  = 0x08; ledShow[0][7]  = 0x10;
  299.         ledShow[0][8]  = 0x10; ledShow[0][9]  = 0x08;
  300.         ledShow[0][10] = 0x26; ledShow[0][11] = 0x64;
  301.         ledShow[0][12] = 0x20; ledShow[0][13] = 0x04;
  302.         ledShow[0][14] = 0x20; ledShow[0][15] = 0x04;
  303.         
  304.         ledShow[0][16] = 0x20; ledShow[0][17] = 0x04;
  305.         ledShow[0][18] = 0x22; ledShow[0][19] = 0x44;
  306.         ledShow[0][20] = 0x21; ledShow[0][21] = 0x84;
  307.         ledShow[0][22] = 0x10; ledShow[0][23] = 0x08;
  308.         ledShow[0][24] = 0x08; ledShow[0][25] = 0x10;
  309.         ledShow[0][26] = 0x07; ledShow[0][27] = 0xE0;
  310.         ledShow[0][28] = 0x00; ledShow[0][29] = 0x00;
  311.         ledShow[0][30] = 0x00; ledShow[0][31] = 0x00;

  312.         if (s4d) {
  313.                 s4d = 0;
  314.                 sysFun = 0;
  315.         }
  316. }

  317. /* 游戏结束 */
  318. void gameOver() {

  319.         // 游戏结束标志
  320.         ledShow[0][0]  = 0x00; ledShow[0][1]  = 0x00;
  321.         ledShow[0][2]  = 0x00; ledShow[0][3]  = 0x00;
  322.         ledShow[0][4]  = 0x07; ledShow[0][5]  = 0xE0;
  323.         ledShow[0][6]  = 0x08; ledShow[0][7]  = 0x10;
  324.         ledShow[0][8]  = 0x10; ledShow[0][9]  = 0x08;
  325.         ledShow[0][10] = 0x26; ledShow[0][11] = 0x64;
  326.         ledShow[0][12] = 0x20; ledShow[0][13] = 0x04;
  327.         ledShow[0][14] = 0x20; ledShow[0][15] = 0x04;
  328.         
  329.         ledShow[0][16] = 0x20; ledShow[0][17] = 0x04;
  330.         ledShow[0][18] = 0x21; ledShow[0][19] = 0x84;
  331.         ledShow[0][20] = 0x22; ledShow[0][21] = 0x44;
  332.         ledShow[0][22] = 0x10; ledShow[0][23] = 0x08;
  333.         ledShow[0][24] = 0x08; ledShow[0][25] = 0x10;
  334.         ledShow[0][26] = 0x07; ledShow[0][27] = 0xE0;
  335.         ledShow[0][28] = 0x00; ledShow[0][29] = 0x00;
  336.         ledShow[0][30] = 0x00; ledShow[0][31] = 0x00;

  337.         if (s4d) {
  338.                 s4d = 0;
  339.                 sysFun = 0;
  340.         }
  341. }

  342. /* 初始化定时器,做为动态扫描 */
  343. void init_Timer1(void)
  344. {
  345.         TMOD |= 0x11;                             
  346.         EA=1;                                                      //总中断使能
  347.         ET1=1;                                                     //定时中断使能
  348.         TR1=1;                                                     //打开定时器开关

  349.         TR0=1;                                                                           // start
  350.         TH0=0xEC;
  351.         TL0=0x78;
  352.         ET0=1;        
  353. }

  354. // 一次写入两个字节
  355. void input2Byte(unsigned char dataR1)                 //写两个字节
  356. {
  357.         unsigned char i;

  358.         bit temp = 0;
  359.         for(i=0; i<8; i++)
  360.         {
  361.                  R1 = !(dataR1 & dotDis[i]);                // 调整成较为方便的看的顺序
  362.                                  
  363.                  T_CLK = 0;
  364.                  T_CLK = 1;
  365.          }
  366. }

  367. // 定时器执行动态扫描整个点阵
  368. void timer1_isr(void) interrupt 3
  369. {
  370.          static unsigned char count;
  371.         unsigned char i;
  372.          
  373.         TH1=0xFF;                                                                //重装初值
  374.         TL1=0;

  375.         T_STR=0;                                                               // 锁存释放

  376.         input2Byte(ledShow[0][i]);
  377.         input2Byte(ledShow[0][i+1]);
  378.         OE=1;                                                                          // 暂时关闭屏幕,防止出现鬼影,如果没有使用该引脚控制则会出现拖影现象。
  379.         T_STR=1;                                                              // 锁存有效,此时一行的数据显示到屏上
  380.         P3=DIS[15-count]|0xF0;                                        // 用P0口的前4位控制16行,屏内部通过4-16译码器工作,循环扫描其他15行
  381.         OE=0;                                                                        // 使能

  382.         count++;
  383.         i+=2;                                                              // 累加调用下一行数据
  384.         if(count==16) count=0;
  385.         if(i==32)            i=0;                                                // 又从第一个位置扫描
  386. }

  387. // 中断0 ,产生移动信号
  388. void init_timer0()interrupt 1 using 1{
  389.         static unsigned char count = 0;
  390.         TR0=0;
  391.         TH0=0xEC;
  392.         TL0=0x78;
  393.         TR0=1;

  394.         f_num = 1;                                                                // 5ms显示一次数码管

  395.         count++;
  396.         if (count >= speed) {
  397.                 count = 0;
  398.                 move = 1;
  399.         }
  400. }
  401. ……………………

  402. …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码

所有代码51hei提供下载:
弹球小游戏-源代码.zip (53.77 KB, 下载次数: 56)

评分

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

查看全部评分

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

使用道具 举报

沙发
ID:355644 发表于 2018-6-21 00:21 | 只看该作者
楼主我想问你接线图怎么接的
回复

使用道具 举报

板凳
ID:352709 发表于 2018-6-21 09:37 | 只看该作者
怎么仿真
回复

使用道具 举报

地板
ID:380389 发表于 2018-8-28 18:40 来自手机 | 只看该作者
感谢楼主分享,学习一下
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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