你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

设计小游戏谷歌小恐龙基于STM32

[复制链接]
STMCU小助手 发布时间:2023-3-24 21:00
前言
使用STM32的显示屏其实可以开发出许多有趣的小项目,比如:多功能菜单,小游戏等等。其中,STM32F1XX由于Cortex-M3芯片的性能一般(计算量与内存),所以能够实现的小游戏不多,较为常见的:贪吃蛇,俄罗斯方块,飞机大战等。

本文将给大家实现一款较为新颖的小游戏—谷歌小恐龙(Chrome Dino Game)。

简单使用0.96寸OLED屏幕搭配STM32F1系列的MCU就可以实现,硬件要求很低。(本游戏代码基于HAL库实现,文末有代码开源)

实验硬件:STM32F103ZET6;0.96寸OLED;2个KEY按键

硬件实物图:

微信图片_20230323220114.png
效果图:

微信图片_20230323220112.png

引脚连接:
  1. OLED模块:

  2. VCC --> 3.3V

  3. GND --> GND

  4. SCL --> PB10

  5. SDA --> PB11
复制代码

  1. KEY按键模块:

  2. KEY0 --> PE3

  3. KEY1 --> PE4

  4. 注意:这里按键直接采用了正点原子精英板上的固有按键,自己打板的话,视情况下而定。
复制代码

一、谷歌小恐龙简介

谷歌小恐龙(Chrome Dino Game)顾名思义是由Google公司首创出来的小游戏。其初始目的为在Google浏览器出现互联网信号丢失时,排解用户等待联网信号时的无聊难受。

这个游戏的最大优点是它可以在没有互联网的情况下玩。这是Chrome浏览器中一款原始的无止境跑步游戏。主角是一只可爱的霸王龙,它在古老的沙漠中小跑。

当然,恐龙游戏有它的目的:避免仙人掌和翼手龙。虽然游戏看起来很简单,但并不需要很长时间就能变得很难,因为游戏的速度会随着你的进步而不断提高。

本文就以谷歌小恐龙(Chrome Dino Game)游戏为原型,使用STM32于0.96寸OLED屏幕上尽可能地复现了谷歌小恐龙游戏。

微信图片_20230323220105.png



谷歌小恐龙(Chrome Dino Game)实机效果:


微信图片_20230323220103.png

二、OLED简介

关于OLED的使用与原理不熟悉的笔者欢迎去笔者另一篇文章学习,由于篇幅问题,这里就不过多讲诉。

三、KEY按键

开发板上除了有经典的流水灯之外,还有一个必备的练习硬件—按键(key)。

正常地独立按键KEY其实使用很简单,就是基于GPIO引脚的读取操作。唯一需要注意的点:按键按下去之后到底时低电平还是高电平。

笔者这里直接使用了正点原子精英版STM32上的按键KEY,按键原理图如下:

微信图片_20230323220059.png

考虑到本次小游戏只使用2个按键KEY,这里取KEY0和KEY1。KEY0和KEY1按下后为低电平有效。(这里读者朋友可以根据实际情况去设置)


四、CubeMX配置

1、RCC配置外部高速晶振(精度更高)—HSE;

微信图片_20230323220055.png
2、SYS配置:Debug设置成Serial Wire(否则可能导致芯片自锁);

微信图片_20230323220053.png

3、I2C2配置:这里不直接使用CubeMX的I2C2,使用GPIO模拟(PB10:CLK;PB11:SDA)

微信图片_20230323220046.png

4、KEY按键配置:PE3与PE4设置为端口输入(开发板原理图)

微信图片_20230323220049.png

5、时钟树配置:

微信图片_20230323220043.png

6、工程配置

微信图片_20230323220040.png

五、代码讲解

5.1 OLED驱动代码

此部分OLED的基本驱动函数,笔者使用的是I2C驱动的0.96寸OLED屏幕。

所以,首先需要使用GPIO模拟I2C通讯。随后,使用I2C通讯去驱动OLED。
oled.h:
  1. #ifndef __OLED_H
  2. #define __OLED_H

  3. #include "main.h"

  4. #define u8 uint8_t
  5. #define u32 uint32_t

  6. #define OLED_CMD  0  //写命令
  7. #define OLED_DATA 1  //写数据

  8. #define OLED0561_ADD  0x78  // OLED I2C地址
  9. #define COM        0x00  // OLED
  10. #define DAT       0x40  // OLED

  11. #define OLED_MODE 0
  12. #define SIZE 8
  13. #define XLevelL    0x00
  14. #define XLevelH    0x10
  15. #define Max_Column  128
  16. #define Max_Row    64
  17. #define  Brightness  0xFF
  18. #define X_WIDTH   128
  19. #define Y_WIDTH   64


  20. //-----------------OLED IIC GPIO进行模拟----------------

  21. #define OLED_SCLK_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_RESET) //GPIO_ResetBits(GPIOB,GPIO_Pin_10)//SCL
  22. #define OLED_SCLK_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_10, GPIO_PIN_SET) //GPIO_SetBits(GPIOB,GPIO_Pin_10)

  23. #define OLED_SDIN_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_RESET) // GPIO_ResetBits(GPIOB,GPIO_Pin_11)//SDA
  24. #define OLED_SDIN_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11, GPIO_PIN_SET) // GPIO_SetBits(GPIOB,GPIO_Pin_11)


  25. //I2C GPIO模拟
  26. void IIC_Start();
  27. void IIC_Stop();
  28. void IIC_WaitAck();
  29. void IIC_WriteByte(unsigned char IIC_Byte);
  30. void IIC_WriteCommand(unsigned char IIC_Command);
  31. void IIC_WriteData(unsigned char IIC_Data);
  32. void OLED_WR_Byte(unsigned dat,unsigned cmd);


  33. //功能函数
  34. void OLED_Init(void);
  35. void OLED_WR_Byte(unsigned dat,unsigned cmd);

  36. void OLED_FillPicture(unsigned char fill_Data);
  37. void OLED_SetPos(unsigned char x, unsigned char y);
  38. void OLED_DisplayOn(void);
  39. void OLED_DisplayOff(void);
  40. void OLED_Clear(void);
  41. void OLED_On(void);
  42. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
  43. u32 oled_pow(u8 m,u8 n);
  44. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2);
  45. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size);

  46. #endif
复制代码

oled.c:

  1. #include "oled.h"
  2. #include "asc.h"    //字库(可以自己制作)
  3. #include "main.h"



  4. /********************GPIO 模拟I2C*******************/
  5. //注意:这里没有直接使用HAL库中的模拟I2C
  6. /**********************************************
  7. //IIC Start
  8. **********************************************/
  9. void IIC_Start()
  10. {

  11.   OLED_SCLK_Set() ;
  12.   OLED_SDIN_Set();
  13.   OLED_SDIN_Clr();
  14.   OLED_SCLK_Clr();
  15. }

  16. /**********************************************
  17. //IIC Stop
  18. **********************************************/
  19. void IIC_Stop()
  20. {
  21.   OLED_SCLK_Set() ;
  22.   OLED_SDIN_Clr();
  23.   OLED_SDIN_Set();

  24. }

  25. void IIC_WaitAck()
  26. {
  27.   OLED_SCLK_Set() ;
  28.   OLED_SCLK_Clr();
  29. }
  30. /**********************************************
  31. // IIC Write byte
  32. **********************************************/

  33. void IIC_WriteByte(unsigned char IIC_Byte)
  34. {
  35.   unsigned char i;
  36.   unsigned char m,da;
  37.   da=IIC_Byte;
  38.   OLED_SCLK_Clr();
  39.   for(i=0;i<8;i++)
  40.   {
  41.       m=da;
  42.     //  OLED_SCLK_Clr();
  43.     m=m&0x80;
  44.     if(m==0x80)
  45.     {OLED_SDIN_Set();}
  46.     else OLED_SDIN_Clr();
  47.       da=da<<1;
  48.     OLED_SCLK_Set();
  49.     OLED_SCLK_Clr();
  50.   }


  51. }
  52. /**********************************************
  53. // IIC Write Command
  54. **********************************************/
  55. void IIC_WriteCommand(unsigned char IIC_Command)
  56. {
  57.    IIC_Start();
  58.    IIC_WriteByte(0x78);            //Slave address,SA0=0
  59.   IIC_WaitAck();
  60.    IIC_WriteByte(0x00);      //write command
  61.   IIC_WaitAck();
  62.    IIC_WriteByte(IIC_Command);
  63.   IIC_WaitAck();
  64.    IIC_Stop();
  65. }
  66. /**********************************************
  67. // IIC Write Data
  68. **********************************************/
  69. void IIC_WriteData(unsigned char IIC_Data)
  70. {
  71.    IIC_Start();
  72.    IIC_WriteByte(0x78);      //D/C#=0; R/W#=0
  73.   IIC_WaitAck();
  74.    IIC_WriteByte(0x40);      //write data
  75.   IIC_WaitAck();
  76.    IIC_WriteByte(IIC_Data);
  77.   IIC_WaitAck();
  78.    IIC_Stop();
  79. }

  80. void OLED_WR_Byte(unsigned dat,unsigned cmd)
  81. {
  82.   if(cmd)
  83.   {
  84.     IIC_WriteData(dat);
  85.   }
  86.   else
  87.   {
  88.     IIC_WriteCommand(dat);
  89.   }
  90. }

  91. void OLED_Init(void)
  92. {
  93.   HAL_Delay(100);    //这个延迟很重要
  94.   
  95.   OLED_WR_Byte(0xAE,OLED_CMD);//--display off
  96.   OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
  97.   OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
  98.   OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
  99.   OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
  100.   OLED_WR_Byte(0x81,OLED_CMD); // contract control
  101.   OLED_WR_Byte(0xFF,OLED_CMD);//--128
  102.   OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
  103.   OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
  104.   OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
  105.   OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
  106.   OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
  107.   OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
  108.   OLED_WR_Byte(0x00,OLED_CMD);//

  109.   OLED_WR_Byte(0xD5,OLED_CMD);//set osc division
  110.   OLED_WR_Byte(0x80,OLED_CMD);//

  111.   OLED_WR_Byte(0xD8,OLED_CMD);//set area color mode off
  112.   OLED_WR_Byte(0x05,OLED_CMD);//

  113.   OLED_WR_Byte(0xD9,OLED_CMD);//Set Pre-Charge Period
  114.   OLED_WR_Byte(0xF1,OLED_CMD);//

  115.   OLED_WR_Byte(0xDA,OLED_CMD);//set com pin configuartion
  116.   OLED_WR_Byte(0x12,OLED_CMD);//

  117.   OLED_WR_Byte(0xDB,OLED_CMD);//set Vcomh
  118.   OLED_WR_Byte(0x30,OLED_CMD);//

  119.   OLED_WR_Byte(0x8D,OLED_CMD);//set charge pump enable
  120.   OLED_WR_Byte(0x14,OLED_CMD);//

  121.   OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panel
  122.   HAL_Delay(100);  
  123.   OLED_FillPicture(0x0);

  124. }


  125. /********************************************
  126. // OLED_FillPicture
  127. ********************************************/
  128. void OLED_FillPicture(unsigned char fill_Data)
  129. {
  130.   unsigned char m,n;
  131.   for(m=0;m<8;m++)
  132.   {
  133.     OLED_WR_Byte(0xb0+m,0);    //page0-page1
  134.     OLED_WR_Byte(0x00,0);    //low column start address
  135.     OLED_WR_Byte(0x10,0);    //high column start address
  136.     for(n=0;n<128;n++)
  137.       {
  138.         OLED_WR_Byte(fill_Data,1);
  139.       }
  140.   }
  141. }

  142. //坐标设置
  143. void OLED_SetPos(unsigned char x, unsigned char y)
  144. {   OLED_WR_Byte(0xb0+y,OLED_CMD);
  145.   OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
  146.   OLED_WR_Byte((x&0x0f),OLED_CMD);
  147. }
  148. //开启OLED显示
  149. void OLED_DisplayOn(void)
  150. {
  151.   OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  152.   OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
  153.   OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
  154. }
  155. //关闭OLED显示
  156. void OLED_DisplayOff(void)
  157. {
  158.   OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
  159.   OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
  160.   OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
  161. }
  162. //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
  163. void OLED_Clear(void)
  164. {
  165.   u8 i,n;
  166.   for(i=0;i<8;i++)
  167.   {
  168.     OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  169.     OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  170.     OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
  171.     for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
  172.   } //更新显示
  173. }
  174. void OLED_On(void)
  175. {
  176.   u8 i,n;
  177.   for(i=0;i<8;i++)
  178.   {
  179.     OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
  180.     OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
  181.     OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
  182.     for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
  183.   } //更新显示
  184. }
  185. //在指定位置显示一个字符,包括部分字符
  186. //x:0~127
  187. //y:0~63
  188. //mode:0,反白显示;1,正常显示
  189. //size:选择字体 16/12
  190. void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
  191. {
  192.   unsigned char c=0,i=0;
  193.     c=chr-' ';//得到偏移后的值
  194.     if(x>Max_Column-1){x=0;y=y+2;}
  195.     if(Char_Size ==16)
  196.       {
  197.       OLED_SetPos(x,y);
  198.       for(i=0;i<8;i++)
  199.       OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
  200.       OLED_SetPos(x,y+1);
  201.       for(i=0;i<8;i++)
  202.       OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
  203.       }
  204.       else {
  205.         OLED_SetPos(x,y);
  206.         for(i=0;i<6;i++)
  207.         OLED_WR_Byte(F6x8[c][i],OLED_DATA);

  208.       }
  209. }

  210. //m^n函数
  211. u32 oled_pow(u8 m,u8 n)
  212. {
  213.   u32 result=1;
  214.   while(n--)result*=m;
  215.   return result;
  216. }

  217. //显示2个数字
  218. //x,y :起点坐标
  219. //len :数字的位数
  220. //size:字体大小
  221. //mode:模式  0,填充模式;1,叠加模式
  222. //num:数值(0~4294967295);
  223. void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
  224. {
  225.   u8 t,temp;
  226.   u8 enshow=0;
  227.   for(t=0;t<len;t++)
  228.   {
  229.     temp=(num/oled_pow(10,len-t-1))%10;
  230.     if(enshow==0&&t<(len-1))
  231.     {
  232.       if(temp==0)
  233.       {
  234. //        OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
  235.         OLED_ShowChar(x+(size2/2)*t,y,'0',size2);
  236.         continue;
  237.       }else enshow=1;

  238.     }
  239.      OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
  240.   }
  241. }

  242. //显示一个字符号串
  243. void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
  244. {
  245.   unsigned char j=0;
  246.   while (chr[j]!='\0')
  247.   {    OLED_ShowChar(x,y,chr[j],Char_Size);
  248.       x+=8;
  249.     if(x>120){x=0;y+=2;}
  250.       j++;
  251.   }
  252. }
复制代码

5.2 谷歌小恐龙游戏图形绘制代码

该部分为整个项目代码的核心部分之一,任何一个游戏都是需要去绘制和构建游戏的图形以及模型的。好的游戏往往都具有很好的游戏模型和精美UI,很多3A大作都具备这样的特性。

dinogame.h:
  1. #ifndef __DINOGAME_H
  2. #define __DINOGAME_H

  3. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
  4. void OLED_DrawBMPFast(const unsigned char BMP[]);
  5. void oled_drawbmp_block_clear(int bx, int by, int clear_size);
  6. void OLED_DrawGround();
  7. void OLED_DrawCloud();
  8. void OLED_DrawDino();
  9. void OLED_DrawCactus();
  10. int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset);
  11. int OLED_DrawDinoJump(char reset);
  12. void OLED_DrawRestart();
  13. void OLED_DrawCover();

  14. #endif
复制代码

dinogame.c代码:
  1. #include "oled.h"
  2. #include "oledfont.h"
  3. #include "stdlib.h"

  4. /***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
  5. void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[])
  6. {
  7. unsigned int j=0;
  8. unsigned char x,y;

  9.   if(y1%8==0) y=y1/8;
  10.   else y=y1/8+1;
  11.   for(y=y0;y<y1;y++)
  12.   {
  13.     OLED_SetPos(x0,y);
  14.     for(x=x0;x<x1;x++)
  15.       {
  16.         OLED_WR_Byte(BMP[j++],OLED_DATA);
  17.       }
  18.   }
  19. }



  20. // 快速绘制图像
  21. void OLED_DrawBMPFast(const unsigned char BMP[])
  22. {
  23.   unsigned int j = 0;
  24.   unsigned char x, y;

  25.   for (y = 0; y < 8; y++)
  26.   {
  27.     OLED_SetPos(0, y);
  28.     IIC_Start();
  29.     IIC_WriteByte(0x78);
  30.     IIC_WaitAck();
  31.     IIC_WriteByte(0x40);
  32.     IIC_WaitAck();
  33.     for (x = 0; x < 128; x++)
  34.     {
  35.       IIC_WriteByte(BMP[j++]);
  36.       IIC_WaitAck();
  37.     }
  38.     IIC_Stop();
  39.   }
  40. }

  41. void oled_drawbmp_block_clear(int bx, int by, int clear_size)
  42. {
  43.   unsigned int i;
  44.   OLED_SetPos(bx, by);
  45.   IIC_Start();
  46.   IIC_WriteByte(0x78);
  47.   IIC_WaitAck();
  48.   IIC_WriteByte(0x40);
  49.   IIC_WaitAck();

  50.   for (i = 0; i < clear_size; i++)
  51.   {
  52.     if (bx + i>128) break;
  53.     IIC_WriteByte(0x0);
  54.     IIC_WaitAck();
  55.   }
  56.   IIC_Stop();
  57. }

  58. void OLED_DrawGround()
  59. {
  60.   static unsigned int pos = 0;
  61.   unsigned char speed = 5;
  62.   unsigned int ground_length = sizeof(GROUND);
  63.   unsigned char x;

  64.   OLED_SetPos(0, 7);
  65.   IIC_Start();
  66.   IIC_WriteByte(0x78);
  67.   IIC_WaitAck();
  68.   IIC_WriteByte(0x40);
  69.   IIC_WaitAck();
  70.   for (x = 0; x < 128; x++)
  71.   {
  72.     IIC_WriteByte(GROUND[(x+pos)%ground_length]);
  73.     IIC_WaitAck();
  74.   }
  75.   IIC_Stop();

  76.   pos = pos + speed;
  77.   //if(pos>ground_length) pos=0;
  78. }


  79. // 绘制云朵
  80. void OLED_DrawCloud()
  81. {
  82.   static int pos = 128;
  83.   static char height=0;
  84.   char speed = 3;
  85.   unsigned int i=0;
  86.   int x;
  87.   int start_x = 0;
  88.   int length = sizeof(CLOUD);
  89.   unsigned char byte;

  90.   //if (pos + length <= -speed) pos = 128;

  91.   if (pos + length <= -speed)
  92.   {
  93.     pos = 128;
  94.     height = rand()%3;
  95.   }
  96.   if(pos < 0)
  97.   {
  98.     start_x = -pos;
  99.     OLED_SetPos(0, 1+height);
  100.   }
  101.   else
  102.   {
  103.     OLED_SetPos(pos, 1+height);
  104.   }

  105.   IIC_Start();
  106.   IIC_WriteByte(0x78);
  107.   IIC_WaitAck();
  108.   IIC_WriteByte(0x40);
  109.   IIC_WaitAck();
  110.   for (x = start_x; x < length + speed; x++)
  111.   {
  112.     if (pos + x > 127) break;
  113.     if (x < length) byte = CLOUD[x];
  114.     else byte = 0x0;

  115.     IIC_WriteByte(byte);
  116.     IIC_WaitAck();
  117.   }
  118.   IIC_Stop();

  119.   pos = pos - speed;
  120. }

  121. // 绘制小恐龙
  122. void OLED_DrawDino()
  123. {
  124.   static unsigned char dino_dir = 0;
  125.   unsigned int j=0;
  126.   unsigned char x, y;
  127.   unsigned char byte;

  128.   dino_dir++;
  129.   dino_dir = dino_dir%2;
  130.   for(y=0; y<2; y++)
  131.   {
  132.     OLED_SetPos(16, 6+y);
  133.     IIC_Start();
  134.     IIC_WriteByte(0x78);
  135.     IIC_WaitAck();
  136.     IIC_WriteByte(0x40);
  137.     IIC_WaitAck();
  138.     for (x = 0; x < 16; x++)
  139.     {
  140.       j = y*16 + x;
  141.       byte = DINO[dino_dir][j];

  142.       IIC_WriteByte(byte);
  143.       IIC_WaitAck();
  144.     }
  145.     IIC_Stop();
  146.   }
  147. }

  148. // 绘制仙人掌障碍物
  149. void OLED_DrawCactus()
  150. {
  151.   char speed = 5;
  152.   static int pos = 128;
  153.   int start_x = 0;
  154.   int length = sizeof(CACTUS_2)/2;

  155.   unsigned int j=0;
  156.   unsigned char x, y;
  157.   unsigned char byte;

  158.   if (pos + length <= 0)
  159.   {
  160.     oled_drawbmp_block_clear(0, 6, speed);
  161.     pos = 128;
  162.   }

  163.   for(y=0; y<2; y++)
  164.   {
  165.     if(pos < 0)
  166.     {
  167.       start_x = -pos;
  168.       OLED_SetPos(0, 6+y);
  169.     }
  170.     else
  171.     {
  172.       OLED_SetPos(pos, 6+y);
  173.     }

  174.     IIC_Start();
  175.     IIC_WriteByte(0x78);
  176.     IIC_WaitAck();
  177.     IIC_WriteByte(0x40);
  178.     IIC_WaitAck();

  179.     for (x = start_x; x < length; x++)
  180.     {
  181.       if (pos + x > 127) break;
  182.       j = y*length + x;
  183.       byte = CACTUS_2[j];
  184.       IIC_WriteByte(byte);
  185.       IIC_WaitAck();
  186.     }
  187.     IIC_Stop();
  188.   }
  189.   oled_drawbmp_block_clear(pos + length, 6, speed); // 清除残影
  190.   pos = pos - speed;
  191. }


  192. // 绘制随机出现的仙人掌障碍物
  193. int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset)
  194. {
  195.   char speed = 5;
  196.   static int pos = 128;
  197.   int start_x = 0;
  198.   int length = 0;

  199.   unsigned int i=0, j=0;
  200.   unsigned char x, y;
  201.   unsigned char byte;
  202.   if (reset == 1)
  203.   {
  204.     pos = 128;
  205.     oled_drawbmp_block_clear(0, 6, speed);
  206.     return 128;
  207.   }
  208.   if (ver == 0) length = 8; //sizeof(CACTUS_1) / 2;
  209.   else if (ver == 1) length = 16; //sizeof(CACTUS_2) / 2;
  210.   else if (ver == 2 || ver == 3) length = 24;

  211.   for(y=0; y<2; y++)
  212.   {
  213.     if(pos < 0)
  214.     {
  215.       start_x = -pos;
  216.       OLED_SetPos(0, 6+y);
  217.     }
  218.     else
  219.     {
  220.       OLED_SetPos(pos, 6+y);
  221.     }

  222.     IIC_Start();
  223.     IIC_WriteByte(0x78);
  224.     IIC_WaitAck();
  225.     IIC_WriteByte(0x40);
  226.     IIC_WaitAck();

  227.     for (x = start_x; x < length; x++)
  228.     {
  229.       if (pos + x > 127) break;

  230.       j = y*length + x;
  231.       if (ver == 0) byte = CACTUS_1[j];
  232.       else if (ver == 1) byte = CACTUS_2[j];
  233.       else if(ver == 2) byte = CACTUS_3[j];
  234.       else byte = CACTUS_4[j];

  235.       IIC_WriteByte(byte);
  236.       IIC_WaitAck();
  237.     }
  238.     IIC_Stop();
  239.   }

  240.   oled_drawbmp_block_clear(pos + length, 6, speed);

  241.   pos = pos - speed;
  242.   return pos + speed;
  243. }




  244. // 绘制跳跃小恐龙
  245. int OLED_DrawDinoJump(char reset)
  246. {
  247.   char speed_arr[] = {1, 1, 3, 3, 4, 4, 5, 6, 7};
  248.   static char speed_idx = sizeof(speed_arr)-1;
  249.   static int height = 0;
  250.   static char dir = 0;
  251.   //char speed = 4;

  252.   unsigned int j=0;
  253.   unsigned char x, y;
  254.   char offset = 0;
  255.   unsigned char byte;
  256.   if(reset == 1)
  257.   {
  258.     height = 0;
  259.     dir = 0;
  260.     speed_idx = sizeof(speed_arr)-1;
  261.     return 0;
  262.   }
  263.   if (dir==0)
  264.   {
  265.     height += speed_arr[speed_idx];
  266.     speed_idx --;
  267.     if (speed_idx<0) speed_idx = 0;
  268.   }
  269.   if (dir==1)
  270.   {
  271.     height -= speed_arr[speed_idx];
  272.     speed_idx ++;
  273.     if (speed_idx>sizeof(speed_arr)-1) speed_idx = sizeof(speed_arr)-1;
  274.   }
  275.   if(height >= 31)
  276.   {
  277.     dir = 1;
  278.     height = 31;
  279.   }
  280.   if(height <= 0)
  281.   {
  282.     dir = 0;
  283.     height = 0;
  284.   }
  285.   if(height <= 7) offset = 0;
  286.   else if(height <= 15) offset = 1;
  287.   else if(height <= 23) offset = 2;
  288.   else if(height <= 31) offset = 3;
  289.   else offset = 4;

  290.   for(y=0; y<3; y++) // 4
  291.   {
  292.     OLED_SetPos(16, 5- offset + y);

  293.     IIC_Start();
  294.     IIC_WriteByte(0x78);
  295.     IIC_WaitAck();
  296.     IIC_WriteByte(0x40);
  297.     IIC_WaitAck();
  298.     for (x = 0; x < 16; x++) // 32
  299.     {
  300.       j = y*16 + x; // 32
  301.       byte = DINO_JUMP[height%8][j];

  302.       IIC_WriteByte(byte);
  303.       IIC_WaitAck();
  304.     }
  305.     IIC_Stop();
  306.   }
  307.   if (dir == 0) oled_drawbmp_block_clear(16, 8- offset, 16);
  308.   if (dir == 1) oled_drawbmp_block_clear(16, 4- offset, 16);
  309.   return height;
  310. }

  311. // 绘制重启
  312. void OLED_DrawRestart()
  313. {
  314.   unsigned int j=0;
  315.   unsigned char x, y;
  316.   unsigned char byte;
  317.   //OLED_SetPos(0, 0);
  318.   for (y = 2; y < 5; y++)
  319.   {
  320.     OLED_SetPos(52, y);
  321.     IIC_Start();
  322.     IIC_WriteByte(0x78);
  323.     IIC_WaitAck();
  324.     IIC_WriteByte(0x40);
  325.     IIC_WaitAck();
  326.     for (x = 0; x < 24; x++)
  327.     {
  328.       byte = RESTART[j++];
  329.       IIC_WriteByte(byte);
  330.       IIC_WaitAck();
  331.     }
  332.     IIC_Stop();
  333.   }
  334.   OLED_ShowString(10, 3, "GAME", 16);
  335.   OLED_ShowString(86, 3, "OVER", 16);
  336. }
  337. // 绘制封面
  338. void OLED_DrawCover()
  339. {
  340.   OLED_DrawBMPFast(COVER);
  341. }
复制代码

此部分函数主要是实现快速绘制出游戏所需要的模型组件,模型包括:游戏初始化封面,游戏结束封面,小恐龙(跳跃的小恐龙),沙漠地面,随机出现的仙人掌障碍物(1,2,3个),云朵等。

注意:此部分绘制的属于动态化图片绘制,所绘制的图片会自右向左移动。

关于游戏模型基础组件,采用Img2Lcd2.9软件对图片进行取模,注意考虑到0.96寸的OLED屏幕大小有限,取模图片尽可能小一点。

例子:

取模小恐龙模组:

微信图片_20230323220023.png



Img2Lcd2.9软件如下操作取模:

微信图片_20230323220020.png



其余,游戏图片模组依此法进行取模,注意图片取得的大小。

游戏图片取模库oledfont.h:
  1. #ifndef __OLEDFONT_H
  2. #define __OLEDFONT_H
  3. //该文件主要为DinoGame的图像库
  4. /************************************6*8???************************************/

  5. const unsigned char  GROUND[] =
  6. {
  7. 0xc8, 0xc8, 0xc8, 0x28, 0x28, 0x28, 0x8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x8, 0x8, 0xc8, 0xc8, 0xc8, 0x8, 0x38, 0x38, 0x8,
  8. 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x8, 0x48, 0x48, 0x48, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc8, 0x8,
  9. 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x8, 0x28, 0x28, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38, 0x8, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8,
  10. 0x8, 0x8, 0x8, 0x48, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc8, 0xc8, 0x8, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38, 0x8, 0x8, 0x28, 0x8, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x9, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x8, 0xc9, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x29, 0x8, 0x8, 0x8, 0x8,
  11. 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x49, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x8, 0x8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x28, 0x8, 0x8, 0x48, 0x8, 0x38,
  12. 0x38, 0x8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc8, 0xc8, 0xc8, 0x28, 0x28, 0x28, 0x8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x8, 0x8, 0xc8, 0xc8, 0xc8, 0x8, 0x38, 0x38, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x48, 0x48, 0x48, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8, 0x8, 0xc, 0x6, 0x2, 0x42, 0x42, 0x6, 0xc, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38, 0x8, 0x18, 0x18, 0x10, 0x10, 0x10, 0x10, 0x10, 0x18, 0x18, 0x8, 0x48, 0x8, 0x28, 0x28, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x38, 0x38, 0x68, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x48, 0x48, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0xc8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x38, 0x38, 0x8, 0x8, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x8, 0xc8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0xc, 0x4, 0x6, 0x2, 0x2, 0x6, 0xc, 0x4c, 0x48, 0x8, 0x8, 0x8, 0xc, 0x4, 0x6, 0x2, 0x2, 0x6, 0xc, 0xc, 0x68, 0x68, 0x8, 0x28, 0x28, 0x28, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x68, 0x68, 0x68, 0x8, 0x8, 0xc8, 0xc8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x28, 0x28, 0x28, 0x28, 0x8, 0x8, 0x8,
  13. 0x8, 0x8, 0x28, 0x28, 0x28, 0x8, 0x8, 0x48, 0x28, 0x38, 0x38, 0x8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8,
  14. };

  15. const unsigned char  CLOUD[] =
  16. {
  17.   0x80, 0xc0, 0xe0, 0x70, 0xb0, 0xb0, 0xb0, 0x98, 0x88, 0x8e, 0x83, 0x83, 0x83, 0x81, 0x81, 0x93, 0x8e, 0x8c, 0x88, 0x88, 0x98, 0xb0, 0xf0, 0xc0
  18. };

  19. const unsigned char  DINO[2][32] =
  20. {
  21. 0xe0, 0x80, 0x0, 0x0, 0x0, 0x80, 0xc0, 0xe0, 0xfe, 0xff, 0xfd, 0xbf, 0xaf, 0x2f, 0x2f, 0xe, 0x3, 0x7, 0xf, 0x1e, 0xff, 0xbf, 0x1f, 0x1f, 0x3f, 0x2f, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0,
  22. 0xe0, 0x80, 0x0, 0x0, 0x0, 0x80, 0xc0, 0xe0, 0xfe, 0xff, 0xfd, 0xbf, 0xaf, 0x2f, 0x2f, 0xe, 0x3, 0x7, 0xf, 0x1e, 0x3f, 0x7f, 0x5f, 0x3f, 0xff, 0x8f, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0
  23. };


  24. const unsigned char  DINO_JUMP[8][48] =  //
  25. {
  26. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0x80, 0x0, 0x0, 0x0, 0x80, 0xc0, 0xc0, 0xfe, 0xff, 0xfd, 0xbf, 0xaf, 0x2f, 0x2f, 0xe, 0x3, 0x7, 0xf, 0x1f, 0xff, 0xbf, 0x1f, 0x3f, 0xff, 0x8f, 0x7, 0x0, 0x1, 0x0, 0x0, 0x0,

  27. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x0, 0xf0, 0xc0, 0x80, 0x80, 0x80, 0xc0, 0xe0, 0xe0, 0xff, 0xff, 0xfe, 0x5f, 0xd7, 0x17, 0x17, 0x7, 0x1, 0x3, 0x7, 0xf, 0x7f, 0x5f, 0xf, 0x1f, 0x7f, 0x47, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0,

  28. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xc0, 0x40, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0xf8, 0xe0, 0xc0, 0xc0, 0xc0, 0xe0, 0xf0, 0xf0, 0xff, 0xff, 0xff, 0x2f, 0x6b, 0xb, 0xb, 0x3, 0x0, 0x1, 0x3, 0x7, 0x3f, 0x2f, 0x7, 0xf, 0x3f, 0x23, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0,

  29. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0, 0xe0, 0xa0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0x7c, 0xf0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf8, 0xf8, 0xff, 0xff, 0xff, 0x17, 0x35, 0x5, 0x5, 0x1, 0x0, 0x0, 0x1, 0x3, 0x1f, 0x17, 0x3, 0x7, 0x1f, 0x11, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

  30. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0xf0, 0xd0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0x3e, 0x78, 0xf0, 0xf0, 0xf0, 0xf8, 0xfc, 0xfc, 0xff, 0xff, 0x7f, 0xb, 0x1a, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x1, 0xf, 0xb, 0x1, 0x3, 0xf, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

  31. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xf8, 0xe8, 0xf8, 0x78, 0x78, 0x78, 0x70, 0x1f, 0x3c, 0x78, 0xf8, 0xf8, 0xfc, 0xfe, 0xfe, 0xff, 0x7f, 0x3f, 0x5, 0xd, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7,
  32. 0x5, 0x0, 0x1, 0x7, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

  33. 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf8, 0xfc, 0xf4, 0xfc, 0xbc, 0xbc, 0xbc, 0x38, 0xf, 0x1e, 0x3c, 0x7c, 0xfc, 0xfe, 0x7f, 0xff, 0xff, 0x3f, 0x1f, 0x2, 0x6, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3,
  34. 0x2, 0x0, 0x0, 0x3, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

  35. 0xc0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0xfc, 0xfe, 0xfa, 0x7e, 0x5e, 0x5e, 0x5e, 0x1c, 0x7, 0xf, 0x1e, 0x3e, 0xfe, 0x7f, 0x3f, 0x7f, 0xff, 0x1f, 0xf, 0x1, 0x3, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1,
  36. 0x1, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  37. };


  38. const unsigned char  CACTUS_1[] = {
  39.   0xf0, 0xf0, 0x0, 0xff, 0xff, 0x0, 0xf0, 0xf0, 0x3, 0x7, 0x86, 0xff, 0xff, 0x6, 0x3, 0x1
  40. };

  41. const unsigned char  CACTUS_2[] = {
  42.   0xf0, 0xe0, 0x0, 0xff, 0xfe, 0x80, 0xfc, 0x0, 0x0, 0x7c, 0xc0, 0xfe, 0xff, 0x0, 0x80, 0xfc,
  43.   0x3, 0x7, 0x6, 0xff, 0xff, 0x1, 0x10, 0x90, 0x90, 0x90, 0x0, 0xff, 0xff, 0x3, 0x3, 0x1
  44. };

  45. const unsigned char  CACTUS_3[] = {
  46.   0xf0, 0xe0, 0x0, 0xff, 0xfe, 0x80, 0xfc, 0x0, 0xfc, 0xfe, 0x0, 0xff, 0xff, 0x0, 0xf8, 0xf0,
  47.   0x0, 0xfe, 0x80, 0xfe, 0xff, 0xfe, 0x78, 0xfc, 0x13, 0x17, 0x6, 0xff, 0xff, 0x1, 0x10, 0x10,
  48.   0x13, 0x37, 0x4, 0xff, 0xff, 0x8, 0xf, 0x17, 0x10, 0x10, 0x1, 0xff, 0xff, 0x3, 0x13, 0x11
  49. };

  50. const unsigned char  CACTUS_4[] = {
  51.   0xf0, 0xe0, 0x0, 0xff, 0xfe, 0x0, 0xf0, 0x0, 0xc0, 0x0, 0xff, 0xfe, 0x60, 0x3c, 0x80, 0x0,
  52.   0x0, 0x7c, 0xc0, 0xfe, 0xff, 0x0, 0xf0, 0xf8, 0x43, 0x47, 0x86, 0xff, 0xff, 0x26, 0xa3,
  53.   0xa0, 0x27, 0x4, 0xff, 0xff, 0x0, 0x8, 0xff, 0x88, 0x2f, 0x0, 0x0, 0xff, 0xff, 0x6, 0x23, 0x21
  54. };

  55. const unsigned char  RESTART[] =
  56. {
  57. 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0xf, 0x1f, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
  58. 0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x7e, 0x7e, 0x7e, 0x78, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
  59. 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
  60. };
  61. const unsigned char  COVER[] = {
  62. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xe0, 0xf0, 0x30, 0x30, 0x30, 0x30, 0x0, 0x0, 0xf0, 0xf0, 0xc0, 0xc0, 0xf0, 0xf0, 0x0, 0x0, 0xf0, 0xf0, 0xb0, 0xb0, 0x70, 0x60, 0x0, 0x0, 0xe0, 0xf0, 0x30, 0x30, 0xf0, 0xe0, 0x0, 0x0, 0xf0, 0xf0, 0x30, 0xf0, 0xf0, 0x30, 0xf0, 0xe0, 0x0, 0xe0, 0xe0, 0x90, 0x90, 0x90, 0x90, 0x90, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  63. 0x0,
  64. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf3, 0xf7, 0x36, 0x36, 0xf6, 0xe6, 0x0, 0xf0, 0xf7, 0x7, 0xc1, 0xc1, 0x37, 0x37, 0xf0, 0xc0, 0x7, 0xc7, 0xe0, 0x30, 0x37, 0x37,
  65. 0xe0, 0xc0, 0x3, 0x7, 0x6, 0xf6, 0xf7, 0xb3, 0xb0, 0xb0, 0xf7, 0xe7, 0x0, 0xf7, 0xf7, 0x0, 0x7, 0xf7, 0xf0, 0x3, 0xe3, 0xf4, 0x34, 0x34, 0xf4, 0xe4, 0x0, 0x0, 0x0, 0x0,
  66. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x10, 0xc, 0x4, 0x14, 0x14, 0x12, 0x11, 0x11, 0x11, 0x10, 0x11, 0x12, 0x12, 0x12, 0x14, 0x1c, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  67. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf, 0xf, 0xc, 0xc, 0xf, 0x7, 0x0, 0xf, 0xf, 0x0, 0xf, 0xf, 0x0, 0x0, 0xf, 0xf, 0x0, 0x3, 0x7, 0xc, 0xc, 0xc, 0x7, 0x3, 0x0, 0x0, 0x0, 0xf, 0xf, 0x1, 0x1, 0x1, 0xe, 0xe, 0x0, 0x7, 0xf, 0xc, 0xc, 0x7, 0x7, 0x0, 0xf, 0xf, 0x0, 0x0, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0xc0, 0x60, 0xa0, 0xa0, 0xa0, 0x90, 0x88, 0x88, 0x8c, 0x88, 0x90, 0x90, 0xb0, 0xa0, 0xc0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  68. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x40, 0x0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x0, 0x0, 0xf0, 0xfc, 0xfc, 0x9c, 0x9c, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf0, 0xf0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  69. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  70. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x0, 0x0, 0x8, 0x0, 0x0, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x80, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0x4f, 0xf, 0xf, 0xf, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe, 0xfe, 0xfe, 0x0, 0x0, 0xf0, 0xe0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0xf8, 0xf0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x80, 0x80, 0x80, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  71. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xf8, 0xf8, 0xe0, 0xe0, 0x80, 0x80, 0x80, 0xc0, 0xe0, 0xf8, 0xf8, 0xf8, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x18, 0x8, 0x38, 0x38, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0x1, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0xff, 0xff, 0x0, 0xfc, 0xfe, 0x4, 0x0, 0xff, 0xff, 0xff, 0xc, 0xc, 0x8f, 0x83, 0x0, 0xf0, 0xf0, 0x0, 0x80, 0x9f, 0x3f, 0x7f, 0x70, 0x70, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x0, 0xff, 0xff, 0x0, 0x0, 0x0, 0x0, 0x0,
  72. 0x0, 0x0, 0x0, 0x0,
  73. 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x3, 0x7, 0xf, 0x1f, 0x1f, 0x7f, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0x7f, 0x1f, 0x17, 0x7, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x3, 0x7, 0x7, 0x7, 0xff, 0xff, 0xff, 0xff, 0x3, 0x3, 0x1, 0x0, 0x0, 0x3, 0x7, 0xe, 0xc, 0xff, 0xff, 0xff,
  74. 0x0, 0x0, 0x1f, 0x3f, 0x20, 0xff, 0xff, 0x20, 0x1f, 0xf, 0x0, 0x0, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0x3, 0x3, 0x3, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
  75. 0x82, 0x82, 0x82, 0x2, 0x2, 0x22, 0x22, 0x22, 0x22, 0x2, 0x2, 0x2, 0x82, 0x82, 0x0, 0x0, 0x0, 0x1, 0xff, 0x9f, 0x9f, 0x7, 0x7, 0x1, 0x1, 0x7, 0x7, 0xff, 0x80, 0x80, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0xc2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x82, 0x82, 0x82, 0x82, 0x2, 0x2, 0x32, 0x32, 0x32, 0x22, 0x2, 0x2, 0x2, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x42, 0x42, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0, 0xf, 0xf, 0xf, 0xf, 0x0, 0x1, 0x1, 0x1, 0x11, 0x11, 0x1, 0x1, 0x0, 0xf, 0xf, 0xf, 0x0, 0x1, 0x31, 0x11, 0x0, 0xf, 0xf, 0x0, 0xd, 0xd, 0x1, 0x11, 0x11, 0x10, 0x1f, 0x1f, 0x1f, 0x1f, 0x10, 0x0, 0xd, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xd, 0xd, 0x1, 0x0, 0x0,
  76. };


  77. #endif
复制代码

5.3 游戏运行代码

游戏运行代码,主要包含两个部分:(1)按键代码;(2)游戏运行判定代码

按键代码key:
  1. int get_key_val()
  2. {
  3.   if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
  4.   {
  5.     HAL_Delay(10);            //消抖
  6.     if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
  7.     {
  8.     return 2;
  9.     }
  10.   }
  11.   if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
  12.   {
  13.     HAL_Delay(10);            //消抖
  14.     if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
  15.     {
  16.     return 1;
  17.     }
  18.   }
  19.   return 0;
  20. }


  21. 游戏运行判定代码running:



  22.     if (failed == 1)
  23.     {
  24.       OLED_DrawRestart();

  25.       key_num = get_key_val();
  26.       if (key_num == 2)
  27.       {
  28.         if(score > highest_score) highest_score = score;
  29.         score = 0;
  30.         failed = 0;
  31.         height = 0;
  32.         reset = 1;
  33.         OLED_DrawDinoJump(reset);
  34.         OLED_DrawCactusRandom(cactus_category, reset);
  35.         OLED_Clear();
  36.       }
  37.       continue;
  38.     }


  39.     score ++;
  40.     if (height <= 0) key_num = get_key_val();

  41.     OLED_DrawGround();
  42.     OLED_DrawCloud();

  43.     if (height>0 || key_num == 1) height = OLED_DrawDinoJump(reset);
  44.     else OLED_DrawDino();

  45.     cactus_pos = OLED_DrawCactusRandom(cactus_category, reset);
  46.     if(cactus_category == 0) cactus_length = 8;
  47.     else if(cactus_category == 1) cactus_length = 16;
  48.     else cactus_length = 24;

  49.     if (cactus_pos + cactus_length < 0)
  50.     {
  51.       cactus_category = rand()%4;
  52.       OLED_DrawCactusRandom(cactus_category, 1);
  53.     }

  54.     if ((height < 16) && ( (cactus_pos>=16 && cactus_pos <=32) || (cactus_pos + cactus_length>=16 && cactus_pos + cactus_length <=32)))
  55.     {
  56.       failed = 1;
  57.     }

  58.     OLED_ShowString(35, 0, "HI:", 12);
  59.     OLED_ShowNum(58, 0, highest_score, 5, 12);
  60.     OLED_ShowNum(98, 0, score, 5, 12);


  61.     reset = 0;

  62.     cur_speed = score/20;
  63.     if (cur_speed > 29) cur_speed = 29;
  64.     HAL_Delay(30 - cur_speed);
  65. //    HAL_Delay(500);
  66.     key_num = 0;
  67.     /* USER CODE BEGIN 3 */
  68.   
  69.   }
复制代码

这里简单给大家说明一下,代码原理:根据按键的读取的数值去控制小恐龙的运动状态,同时,屏幕上不断移动和随机生成仙人掌障碍物,得分随着游戏进行增加。花一点时间去读一下程序,还是很好理解的。

(为了复现出原版谷歌小恐龙随时间增加,速度越来越快的特性,这里根据用户得分情况,使用减小延迟函数时间去加快游戏速度提高难度)

转载自: 古月居
如有侵权请联系删除


收藏 评论0 发布时间:2023-3-24 21:00

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版