基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

这篇具有很好参考价值的文章主要介绍了基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

        前言:使用STM32的显示屏其实可以开发出许多有趣的小项目,比如:多功能菜单小游戏等等。其中,STM32F1XX由于Cortex-M3芯片的性能一般计算量与内存),所以能够实现的小游戏不多,较为常见的:贪吃蛇,俄罗斯方块,飞机大战等。本文将给大家实现一款较为新颖的小游戏——谷歌小恐龙(Chrome Dino Game)。简单使用0.96寸OLED屏幕搭配STM32F1系列的MCU就可以实现,硬件要求很低。(本游戏代码基于HAL库实现,文末有代码开源

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

        硬件实物图:

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

        效果图:

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

引脚连接:

OLED模块:

VCC --> 3.3V

GND --> GND

SCL --> PB10

SDA --> PB11

KEY按键模块:

KEY0 --> PE3

KEY1 --> PE4

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

一、谷歌小恐龙(Chrome Dino Game)简介

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

        这个游戏的最大优点是它可以在没有互联网的情况下玩。这是Chrome浏览器中一款原始的无止境跑步游戏。主角是一只可爱的霸王龙,它在古老的沙漠中小跑。当然,恐龙游戏有它的目的:避免仙人掌翼手龙。虽然游戏看起来很简单,但并不需要很长时间就能变得很难,因为游戏的速度会随着你的进步而不断提高。

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

 原游戏网址:谷歌小恐龙在线 - 免费玩谷歌小恐龙 (dino.zone)

二、OLED简介

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

【强烈推荐】基于stm32的OLED各种显示实现(含动态图)_混分巨兽龙某某的博客-CSDN博客_oled显示stm32https://blog.csdn.net/black_sneak/article/details/125418537?spm=1001.2014.3001.5501

三、KEY按键

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

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

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

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

四、CubeMX配置

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

2、SYS配置:Debug设置成Serial Wire否则可能导致芯片自锁);

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game) 3、I2C2配置:这里不直接使用CubeMX的I2C2,使用GPIO模拟(PB10:CLK;PB11:SDA)

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

5、时钟树配置:

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

6、工程配置 

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

五、代码讲解

5.1 OLED驱动代码

        此部分OLED的基本驱动函数,笔者使用的是I2C驱动的0.96寸OLED屏幕。所以,首先需要使用GPIO模拟I2C通讯。随后,使用I2C通讯去驱动OLED。(此部分代码包含了屏幕驱动基础显示,如果对OLED显示不太理解的朋友可以去看看上文提到的笔者的另一篇文章

oled.h:

#ifndef __OLED_H
#define __OLED_H

#include "main.h"

#define u8 uint8_t
#define u32 uint32_t

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

#define OLED0561_ADD	0x78  // OLED I2C地址
#define COM				0x00  // OLED 
#define DAT 			0x40  // OLED 

#define OLED_MODE 0
#define SIZE 8
#define XLevelL		0x00
#define XLevelH		0x10
#define Max_Column	128
#define Max_Row		64
#define	Brightness	0xFF
#define X_WIDTH 	128
#define Y_WIDTH 	64


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

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

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


//I2C GPIO模拟
void IIC_Start();
void IIC_Stop();
void IIC_WaitAck();
void IIC_WriteByte(unsigned char IIC_Byte);
void IIC_WriteCommand(unsigned char IIC_Command);
void IIC_WriteData(unsigned char IIC_Data);
void OLED_WR_Byte(unsigned dat,unsigned cmd);


//功能函数
void OLED_Init(void);
void OLED_WR_Byte(unsigned dat,unsigned cmd);

void OLED_FillPicture(unsigned char fill_Data);
void OLED_SetPos(unsigned char x, unsigned char y);
void OLED_DisplayOn(void);
void OLED_DisplayOff(void);
void OLED_Clear(void);
void OLED_On(void);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
u32 oled_pow(u8 m,u8 n);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2);
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size);

#endif

oled.c:

#include "oled.h"
#include "asc.h"    //字库(可以自己制作)
#include "main.h"
 
 
 
/********************GPIO 模拟I2C*******************/
//注意:这里没有直接使用HAL库中的模拟I2C
/**********************************************
//IIC Start
**********************************************/
void IIC_Start()
{

	OLED_SCLK_Set() ;
	OLED_SDIN_Set();
	OLED_SDIN_Clr();
	OLED_SCLK_Clr();
}

/**********************************************
//IIC Stop
**********************************************/
void IIC_Stop()
{
	OLED_SCLK_Set() ;
	OLED_SDIN_Clr();
	OLED_SDIN_Set();

}

void IIC_WaitAck()
{
	OLED_SCLK_Set() ;
	OLED_SCLK_Clr();
}
/**********************************************
// IIC Write byte
**********************************************/

void IIC_WriteByte(unsigned char IIC_Byte)
{
	unsigned char i;
	unsigned char m,da;
	da=IIC_Byte;
	OLED_SCLK_Clr();
	for(i=0;i<8;i++)
	{
			m=da;
		//	OLED_SCLK_Clr();
		m=m&0x80;
		if(m==0x80)
		{OLED_SDIN_Set();}
		else OLED_SDIN_Clr();
			da=da<<1;
		OLED_SCLK_Set();
		OLED_SCLK_Clr();
	}


}
/**********************************************
// IIC Write Command
**********************************************/
void IIC_WriteCommand(unsigned char IIC_Command)
{
   IIC_Start();
   IIC_WriteByte(0x78);            //Slave address,SA0=0
	IIC_WaitAck();
   IIC_WriteByte(0x00);			//write command
	IIC_WaitAck();
   IIC_WriteByte(IIC_Command);
	IIC_WaitAck();
   IIC_Stop();
}
/**********************************************
// IIC Write Data
**********************************************/
void IIC_WriteData(unsigned char IIC_Data)
{
   IIC_Start();
   IIC_WriteByte(0x78);			//D/C#=0; R/W#=0
	IIC_WaitAck();
   IIC_WriteByte(0x40);			//write data
	IIC_WaitAck();
   IIC_WriteByte(IIC_Data);
	IIC_WaitAck();
   IIC_Stop();
}

void OLED_WR_Byte(unsigned dat,unsigned cmd)
{
	if(cmd)
	{
		IIC_WriteData(dat);
	}
	else
	{
		IIC_WriteCommand(dat);
	}
}
 
void OLED_Init(void)
{
	HAL_Delay(100);		//这个延迟很重要
	
	OLED_WR_Byte(0xAE,OLED_CMD);//--display off
	OLED_WR_Byte(0x00,OLED_CMD);//---set low column address
	OLED_WR_Byte(0x10,OLED_CMD);//---set high column address
	OLED_WR_Byte(0x40,OLED_CMD);//--set start line address
	OLED_WR_Byte(0xB0,OLED_CMD);//--set page address
	OLED_WR_Byte(0x81,OLED_CMD); // contract control
	OLED_WR_Byte(0xFF,OLED_CMD);//--128
	OLED_WR_Byte(0xA1,OLED_CMD);//set segment remap
	OLED_WR_Byte(0xA6,OLED_CMD);//--normal / reverse
	OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)
	OLED_WR_Byte(0x3F,OLED_CMD);//--1/32 duty
	OLED_WR_Byte(0xC8,OLED_CMD);//Com scan direction
	OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset
	OLED_WR_Byte(0x00,OLED_CMD);//

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

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

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

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

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

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

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

}


/********************************************
// OLED_FillPicture
********************************************/
void OLED_FillPicture(unsigned char fill_Data)
{
	unsigned char m,n;
	for(m=0;m<8;m++)
	{
		OLED_WR_Byte(0xb0+m,0);		//page0-page1
		OLED_WR_Byte(0x00,0);		//low column start address
		OLED_WR_Byte(0x10,0);		//high column start address
		for(n=0;n<128;n++)
			{
				OLED_WR_Byte(fill_Data,1);
			}
	}
}

//坐标设置
void OLED_SetPos(unsigned char x, unsigned char y)
{ 	OLED_WR_Byte(0xb0+y,OLED_CMD);
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);
	OLED_WR_Byte((x&0x0f),OLED_CMD);
}
//开启OLED显示
void OLED_DisplayOn(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //DCDC ON
	OLED_WR_Byte(0XAF,OLED_CMD);  //DISPLAY ON
}
//关闭OLED显示
void OLED_DisplayOff(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //DCDC OFF
	OLED_WR_Byte(0XAE,OLED_CMD);  //DISPLAY OFF
}
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!
void OLED_Clear(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
		for(n=0;n<128;n++)OLED_WR_Byte(0,OLED_DATA);
	} //更新显示
}
void OLED_On(void)
{
	u8 i,n;
	for(i=0;i<8;i++)
	{
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址
		for(n=0;n<128;n++)OLED_WR_Byte(1,OLED_DATA);
	} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示
//size:选择字体 16/12
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size)
{
	unsigned char c=0,i=0;
		c=chr-' ';//得到偏移后的值
		if(x>Max_Column-1){x=0;y=y+2;}
		if(Char_Size ==16)
			{
			OLED_SetPos(x,y);
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
			OLED_SetPos(x,y+1);
			for(i=0;i<8;i++)
			OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
			}
			else {
				OLED_SetPos(x,y);
				for(i=0;i<6;i++)
				OLED_WR_Byte(F6x8[c][i],OLED_DATA);

			}
}

//m^n函数
u32 oled_pow(u8 m,u8 n)
{
	u32 result=1;
	while(n--)result*=m;
	return result;
}

//显示2个数字
//x,y :起点坐标
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2)
{
	u8 t,temp;
	u8 enshow=0;
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10;
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
//				OLED_ShowChar(x+(size2/2)*t,y,' ',size2);
				OLED_ShowChar(x+(size2/2)*t,y,'0',size2);
				continue;
			}else enshow=1;

		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2);
	}
}

//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size)
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		OLED_ShowChar(x,y,chr[j],Char_Size);
			x+=8;
		if(x>120){x=0;y+=2;}
			j++;
	}
}

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

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

dinogame.h:

#ifndef __DINOGAME_H
#define __DINOGAME_H

void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void OLED_DrawBMPFast(const unsigned char BMP[]);
void oled_drawbmp_block_clear(int bx, int by, int clear_size);
void OLED_DrawGround();
void OLED_DrawCloud();
void OLED_DrawDino();
void OLED_DrawCactus();
int OLED_DrawCactusRandom(unsigned char ver, unsigned char reset);
int OLED_DrawDinoJump(char reset);
void OLED_DrawRestart();
void OLED_DrawCover();

#endif

dinogame.c代码:

#include "oled.h"
#include "oledfont.h"
#include "stdlib.h"

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

  if(y1%8==0) y=y1/8;
  else y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_SetPos(x0,y);
		for(x=x0;x<x1;x++)
	    {
	    	OLED_WR_Byte(BMP[j++],OLED_DATA);
	    }
	}
}



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

	for (y = 0; y < 8; y++)
	{
		OLED_SetPos(0, y);
		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();
		for (x = 0; x < 128; x++)
		{
			IIC_WriteByte(BMP[j++]);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
}

void oled_drawbmp_block_clear(int bx, int by, int clear_size)
{
	unsigned int i;
	OLED_SetPos(bx, by);
	IIC_Start();
	IIC_WriteByte(0x78);
	IIC_WaitAck();
	IIC_WriteByte(0x40);
	IIC_WaitAck();

	for (i = 0; i < clear_size; i++)
	{
		if (bx + i>128) break;
		IIC_WriteByte(0x0);
		IIC_WaitAck();
	}
	IIC_Stop();
}

void OLED_DrawGround()
{
	static unsigned int pos = 0;
	unsigned char speed = 5;
	unsigned int ground_length = sizeof(GROUND);
	unsigned char x;

	OLED_SetPos(0, 7);
	IIC_Start();
	IIC_WriteByte(0x78);
	IIC_WaitAck();
	IIC_WriteByte(0x40);
	IIC_WaitAck();
	for (x = 0; x < 128; x++)
	{
		IIC_WriteByte(GROUND[(x+pos)%ground_length]);
		IIC_WaitAck();
	}
	IIC_Stop();

	pos = pos + speed;
	//if(pos>ground_length) pos=0;
}


// 绘制云朵
void OLED_DrawCloud()
{
	static int pos = 128;
	static char height=0;
	char speed = 3;
	unsigned int i=0;
	int x;
	int start_x = 0;
	int length = sizeof(CLOUD);
	unsigned char byte;

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

	if (pos + length <= -speed)
	{
		pos = 128;
		height = rand()%3;
	}
	if(pos < 0)
	{
		start_x = -pos;
		OLED_SetPos(0, 1+height);
	}
	else
	{
		OLED_SetPos(pos, 1+height);
	}

	IIC_Start();
	IIC_WriteByte(0x78);
	IIC_WaitAck();
	IIC_WriteByte(0x40);
	IIC_WaitAck();
	for (x = start_x; x < length + speed; x++)
	{
		if (pos + x > 127) break;
		if (x < length) byte = CLOUD[x];
		else byte = 0x0;

		IIC_WriteByte(byte);
		IIC_WaitAck();
	}
	IIC_Stop();

	pos = pos - speed;
}

// 绘制小恐龙
void OLED_DrawDino()
{
	static unsigned char dino_dir = 0;
	unsigned int j=0;
	unsigned char x, y;
	unsigned char byte;

	dino_dir++;
	dino_dir = dino_dir%2;
	for(y=0; y<2; y++)
	{
		OLED_SetPos(16, 6+y);
		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();
		for (x = 0; x < 16; x++)
		{
			j = y*16 + x;
			byte = DINO[dino_dir][j];

			IIC_WriteByte(byte);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
}

// 绘制仙人掌障碍物
void OLED_DrawCactus()
{
	char speed = 5;
	static int pos = 128;
	int start_x = 0;
	int length = sizeof(CACTUS_2)/2;

	unsigned int j=0;
	unsigned char x, y;
	unsigned char byte;

	if (pos + length <= 0)
	{
		oled_drawbmp_block_clear(0, 6, speed);
		pos = 128;
	}

	for(y=0; y<2; y++)
	{
		if(pos < 0)
		{
			start_x = -pos;
			OLED_SetPos(0, 6+y);
		}
		else
		{
			OLED_SetPos(pos, 6+y);
		}

		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();

		for (x = start_x; x < length; x++)
		{
			if (pos + x > 127) break;
			j = y*length + x;
			byte = CACTUS_2[j];
			IIC_WriteByte(byte);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
	oled_drawbmp_block_clear(pos + length, 6, speed); // 清除残影
	pos = pos - speed;
}


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

	unsigned int i=0, j=0;
	unsigned char x, y;
	unsigned char byte;
	if (reset == 1)
	{
		pos = 128;
		oled_drawbmp_block_clear(0, 6, speed);
		return 128;
	}
	if (ver == 0) length = 8; //sizeof(CACTUS_1) / 2;
	else if (ver == 1) length = 16; //sizeof(CACTUS_2) / 2;
	else if (ver == 2 || ver == 3) length = 24;

	for(y=0; y<2; y++)
	{
		if(pos < 0)
		{
			start_x = -pos;
			OLED_SetPos(0, 6+y);
		}
		else
		{
			OLED_SetPos(pos, 6+y);
		}

		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();

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

			j = y*length + x;
			if (ver == 0) byte = CACTUS_1[j];
			else if (ver == 1) byte = CACTUS_2[j];
			else if(ver == 2) byte = CACTUS_3[j];
			else byte = CACTUS_4[j];

			IIC_WriteByte(byte);
			IIC_WaitAck();
		}
		IIC_Stop();
	}

	oled_drawbmp_block_clear(pos + length, 6, speed);

	pos = pos - speed;
	return pos + speed;
}




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

	unsigned int j=0;
	unsigned char x, y;
	char offset = 0;
	unsigned char byte;
	if(reset == 1)
	{
		height = 0;
		dir = 0;
		speed_idx = sizeof(speed_arr)-1;
		return 0;
	}
	if (dir==0)
	{
		height += speed_arr[speed_idx];
		speed_idx --;
		if (speed_idx<0) speed_idx = 0;
	}
	if (dir==1)
	{
		height -= speed_arr[speed_idx];
		speed_idx ++;
		if (speed_idx>sizeof(speed_arr)-1) speed_idx = sizeof(speed_arr)-1;
	}
	if(height >= 31)
	{
		dir = 1;
		height = 31;
	}
	if(height <= 0)
	{
		dir = 0;
		height = 0;
	}
	if(height <= 7) offset = 0;
	else if(height <= 15) offset = 1;
	else if(height <= 23) offset = 2;
	else if(height <= 31) offset = 3;
	else offset = 4;

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

		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();
		for (x = 0; x < 16; x++) // 32
		{
			j = y*16 + x; // 32
			byte = DINO_JUMP[height%8][j];

			IIC_WriteByte(byte);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
	if (dir == 0) oled_drawbmp_block_clear(16, 8- offset, 16);
	if (dir == 1) oled_drawbmp_block_clear(16, 4- offset, 16);
	return height;
}

// 绘制重启
void OLED_DrawRestart()
{
	unsigned int j=0;
	unsigned char x, y;
	unsigned char byte;
	//OLED_SetPos(0, 0);
	for (y = 2; y < 5; y++)
	{
		OLED_SetPos(52, y);
		IIC_Start();
		IIC_WriteByte(0x78);
		IIC_WaitAck();
		IIC_WriteByte(0x40);
		IIC_WaitAck();
		for (x = 0; x < 24; x++)
		{
			byte = RESTART[j++];
			IIC_WriteByte(byte);
			IIC_WaitAck();
		}
		IIC_Stop();
	}
	OLED_ShowString(10, 3, "GAME", 16);
	OLED_ShowString(86, 3, "OVER", 16);
}
// 绘制封面
void OLED_DrawCover()
{
	OLED_DrawBMPFast(COVER);
}

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

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

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

例子:

        取模小恐龙模组:

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

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

基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)

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

游戏图片取模库oledfont.h:

#ifndef __OLEDFONT_H
#define __OLEDFONT_H
//该文件主要为DinoGame的图像库
/************************************6*8???************************************/

const unsigned char  GROUND[] =
{
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,
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,
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,
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,
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,
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,
0x8, 0x8, 0x28, 0x28, 0x28, 0x8, 0x8, 0x48, 0x28, 0x38, 0x38, 0x8, 0x8, 0x8, 0x8, 0xc8, 0x8, 0x8,
};

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

const unsigned char  DINO[2][32] =
{
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,
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
};


const unsigned char  DINO_JUMP[8][48] =  //
{
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,

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,

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,

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,

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,

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,
0x5, 0x0, 0x1, 0x7, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

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,
0x2, 0x0, 0x0, 0x3, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,

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,
0x1, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
};


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

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

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

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

const unsigned char  RESTART[] =
{
0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0x3f, 0x3f, 0xf, 0x1f, 0x3f, 0xff, 0xff, 0xff, 0x3f, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc,
0xff, 0xff, 0xff, 0xff, 0xff, 0x0, 0x0, 0x7e, 0x7e, 0x7e, 0x78, 0x7c, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x0, 0x0, 0xff, 0xff, 0xff, 0xff, 0xff,
0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0x3f,
};
const unsigned char  COVER[] = {
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,
0x0,
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,
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,
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,
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,
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,
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,
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,
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,
0x0, 0x0, 0x0, 0x0,
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,
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,
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,
};


#endif

5.3 游戏运行代码

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

按键代码key:

int get_key_val()
{
	if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
	{
		HAL_Delay(10);            //消抖
		if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==0)
		{
		return 2;
		}
	}
	if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
	{
		HAL_Delay(10);            //消抖
		if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==0)
		{
		return 1;
		}
	}
	return 0;
}

游戏运行判定代码running:

		if (failed == 1)
		{
			OLED_DrawRestart();

			key_num = get_key_val();
			if (key_num == 2)
			{
				if(score > highest_score) highest_score = score;
				score = 0;
				failed = 0;
				height = 0;
				reset = 1;
				OLED_DrawDinoJump(reset);
				OLED_DrawCactusRandom(cactus_category, reset);
				OLED_Clear();
			}
			continue;
		}


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

		OLED_DrawGround();
		OLED_DrawCloud();

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

		cactus_pos = OLED_DrawCactusRandom(cactus_category, reset);
		if(cactus_category == 0) cactus_length = 8;
		else if(cactus_category == 1) cactus_length = 16;
		else cactus_length = 24;

		if (cactus_pos + cactus_length < 0)
		{
		  cactus_category = rand()%4;
			OLED_DrawCactusRandom(cactus_category, 1);
		}

		if ((height < 16) && ( (cactus_pos>=16 && cactus_pos <=32) || (cactus_pos + cactus_length>=16 && cactus_pos + cactus_length <=32)))
		{
			failed = 1;
		}

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


		reset = 0;

		cur_speed = score/20;
		if (cur_speed > 29) cur_speed = 29;
		HAL_Delay(30 - cur_speed);
//		HAL_Delay(500);
		key_num = 0;
    /* USER CODE BEGIN 3 */
  
  }

        这里简单给大家说明一下,代码原理:根据按键的读取的数值去控制小恐龙的运动状态,同时,屏幕上不断移动和随机生成仙人掌障碍物,得分随着游戏进行增加。花一点时间去读一下程序,还是很好理解的。(为了复现出原版谷歌小恐龙随时间增加,速度越来越快的特性,这里根据用户得分情况,使用减小延迟函数时间去加快游戏速度提高难度

六、游戏效果

谷歌小恐龙(Chrome Dino Game)

        笔者是一只手拍摄,一只手玩这个游戏,再加上KEY按键靠得太近,按得不方便,所以反复GG。(小声:好吧,笔者太菜!)实在话,感觉小恐龙跑得太快的话,可以把得分延迟函数基础数值加大一点。

代码开源

链接:https://pan.baidu.com/s/1RHHZ8P3axWi5HQR8MHhagw 提取码:b7uy文章来源地址https://www.toymoban.com/news/detail-454716.html

到了这里,关于基于STM32的小游戏——谷歌小恐龙(Chrome Dino Game)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 基于STM32F407的俄罗斯方块小游戏的设计

        本文讲述的是基于STM32F407的俄罗斯方块小游戏的设计思路和测试结果,具体的代码分析见文章 基于STM32F407的俄罗斯方块游戏代码分析_钻仰弥坚的博客-CSDN博客 1.1 可行性分析 可行性分析能够对新系统进行各方面的分析与研究,确定新系统是否具有开发的可行性和必要性

    2024年02月11日
    浏览(56)
  • python小游戏——跑酷小恐龙代码开源

    ♥️ 作者:小刘在这里 ♥️ 每天分享云计算网络运维课堂笔记,努力不一定有回报,但一定会有收获加油!一起努力,共赴美好人生! ♥️ 夕阳下,是最美的,绽放,愿所有的美好,再疫情结束后如约而至。 目录 一.效果呈现  二.主代码 三.cfg 四.README \\\'\\\'\\\'配置文件\\\'\\\'\\\' imp

    2024年02月15日
    浏览(36)
  • Chrome小恐龙快跑小游戏——Python实现

    目录 视频演示 代码实现   Chrome小恐龙快跑小游戏——Python实现

    2024年02月10日
    浏览(47)
  • 基于STM32 LCD屏实现的俄罗斯方块小游戏(20220522完成 第一个综合类项目)

    本项目基于 正点原子mini(stm32f103RCT6) 2.8 寸的 ALIENTEK TFTLCD 模块 二轴摇杆模块 的俄罗斯方块小游戏。(学习过程中的项目自测) 1.随机数生成我是用RTC的时钟自己写的,用srand+rand 只能生成一次。 2.并行程序(有什么更好的方法)。 3.觉得我哪里需要改进或者有什么见解可以评论

    2024年02月08日
    浏览(70)
  • STM32 Proteus仿真ili9341 TFT2048小游戏 -0067

    STM32 Proteus仿真ili9341 TFT2048小游戏 -0067 Proteus 仿真小实验: STM32 Proteus仿真ili9341 TFT2048小游戏 -0067 功能: 硬件组成:STM32F103R6单片机 +ili9341 TFT显示器+上下左右方向键+赢了按键+输了按键 1.标准2048经典游戏玩法,4*4=16个棋盘,带计时,记分功能。 2.有上、下、左、右4个按

    2024年02月15日
    浏览(35)
  • 录有手就行1、吃金币2、打乒乓3、滑雪4、并夕夕版飞机大战5、打地鼠简简单单6、小恐龙7、消消乐8、俄罗斯方块9、贪吃蛇普普通通10、24点小游戏

    1、吃金币 【有手就行系列不介绍玩法了+附源码】 源码分享:   import os import cfg import sys import pygame import random from modules import *     \\\'\\\'\\\'游戏初始化\\\'\\\'\\\' def initGame():     # 初始化pygame, 设置展示窗口     pygame.init()     screen = pygame.display.set_mode(cfg.SCREENSIZE)     pygame.display.set_capt

    2024年03月21日
    浏览(53)
  • 小游戏实战丨基于PyGame的贪吃蛇小游戏

    本期内容:基于pygame的贪吃蛇小游戏 下载地址:https://download.csdn.net/download/m0_68111267/88700188 实验环境 python3.11及以上 pycharm pygame 安装pygame的命令: pygame是一个开源的Python模块,专门用于编写电子游戏。它使用简单、功能强大,因此非常适合初学者入门。pygame的主要特点包括图

    2024年02月03日
    浏览(63)
  • 小游戏实战丨基于Tkinter的五子棋小游戏

    本期内容:基于tkinter的五子棋小游戏 下载地址:https://download.csdn.net/download/m0_68111267/88700190 实验环境 python3.11及以上 pycharm tkinter Tkinter是Python的一个标准的图形用户界面(GUI)库,它是基于Tk工具包的。Tkinter库提供了GUI应用程序开发所需的各种组件和方法,方便开发者快速创建

    2024年01月22日
    浏览(51)
  • 基于python的小游戏毕业设计,python小游戏毕业设计

    大家好,本文将围绕基于python的小游戏毕业设计展开说明,python小游戏毕业设计是一个很多人都想弄明白的事情,想搞清楚利用python设计小游戏需要先了解以下几个事情。 文章目录 0 项目简介 1 游戏介绍 2 实现效果 3 开发工具 3.1 环境配置 3.2 Pygame介绍 4 具体实现 5 最后 🔥

    2024年01月15日
    浏览(52)
  • 基于C#的2048小游戏

    最近在玩过2048这个小游戏后感觉很有意思,想着正在学C#的winfrom的我能不能自己写一个2048游戏呢?于是就有了这个:   目录 1.实现思路; 2.代码实现; 1.初始化地图表示的数组; 2.绘制游戏的边框; 3.设置每个数值对应的颜色(可省略); 4.添加控件; 5.四个方向的移动;

    2024年02月08日
    浏览(46)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包