智能手表:小恐龙游戏

发布于:2025-08-03 ⋅ 阅读:(11) ⋅ 点赞:(0)

 小恐龙

初始菜单下 Key3 按下进入游戏选择界面呈现 “谷歌小恐龙”,Key2 可下移光标定位该选项,再按 Key3 进入游戏,游戏中 Key3 控制小恐龙起跳、OLED 以 0.1s 为单位计时,小恐龙碰障碍物则触发 “Game Over” 结束游戏 。 

先写一个计分页面,通过计时器0.1s  cnt++ 在定时器中调用

每累计到 100(对应 0.1 秒计时单位)就将分数Score加 1

int Score=0;
//显示分数
void Show_Score(void)
{
	OLED_ShowNum(91,0,Score,5,OLED_6X8);
}
void Dino_Tick(void)
{
	static uint8_t Score_Count=0,Ground_cnt,Cloud_Count;
	Score_Count++;
	Ground_cnt++;
	Cloud_Count++;
	if(Score_Count>=100)//计分 0.1s
	{
		Score_Count=0;
		Score++;
	}
}

写地面向左移动效果

地面的宽为256个像素点 高为8

让其不断向左移动

   

将256分为2组,当一组刚好移动到显示平外时,另一组刚好在屏幕内

每20ms Ground_Pos ++ 标志位加一

OLED_DisplayBuf[7][i]显存数组在 OLED 屏幕的特定行(第 7 行)绘制地面(Ground)图案,并通过偏移 Ground_Pos变量实现地面的滚动效果

Ground[];是取模生成的地面

显存函数就128个  但是Ground的256个

当Ground_Pos<128时,正常显示

当Ground_Pos>128时,比如 Ground_Pos=200, 255-200=55此时地面才有55长度,不够屏幕的宽度,怎么办呢,所以就得从开头的位置截取73的长度,也就是,让Ground_Pos从0计数到73,来补全空余的

//显示地面
uint16_t Ground_Pos;
void Show_Ground(void)
{
	if(Ground_Pos<128)
	{
		for(uint8_t i=0;i<128;i++)
	{
		OLED_DisplayBuf[7][i]=Ground[i+Ground_Pos];
	}
	}
	else 
	{
			for(uint8_t i=0;i<255-Ground_Pos;i++)
		{
			OLED_DisplayBuf[7][i]=Ground[i+Ground_Pos];
		}
			for(uint8_t i=255-Ground_Pos;i<128;i++)
		{
			OLED_DisplayBuf[7][i]=Ground[i-(255-Ground_Pos)];
		}
	}

}
void Dino_Tick(void)
{
	static uint8_t Score_Count=0,Ground_cnt,Cloud_Count;
	Score_Count++;
	Ground_cnt++;
	Cloud_Count++;
	if(Score_Count>=100)//计分 0.1s
	{
		Score_Count=0;
		Score++;
	}
	if(Ground_cnt>=20)
	{
	Ground_cnt=0;//20ms地面 和 仙人掌一起移动
	Ground_Pos++;
	Barrier_Pos++;
		if(Ground_Pos>=256)Ground_Pos=0;
		if(Barrier_Pos>=144) Barrier_Pos=0;
	}
}

写障碍物显示的函数

当障碍物移动过去时,才显示取一次随机数

barrier_flag用于选择障碍物类型(随机取 0-2),Barrier_Pos记录障碍物偏移位置;当偏移量≥143 时重新随机切换障碍物类型,通过OLED_ShowImage在 (127-Barrier_Pos,44) 位置显示 16x18 大小的障碍物图像。

//障碍物
uint8_t barrier_flag;
uint8_t Barrier_Pos;
struct Object_Position barrier;
void Show_Barrier(void)
{
	if(Barrier_Pos>=143)
	{
	barrier_flag=rand()%3;
	}
	OLED_ShowImage(127-Barrier_Pos,44,16,18,Barrier[barrier_flag]);
	
	barrier.minX=127-Barrier_Pos;
	barrier.maxX=127-Barrier_Pos+16;
	barrier.minY=44;
	barrier.maxY=44+18;

}
void Dino_Tick(void)
{
	static uint8_t Score_Count=0,Ground_cnt,Cloud_Count;
	Score_Count++;
	Ground_cnt++;
	Cloud_Count++;
	if(Score_Count>=100)//计分 0.1s
	{
		Score_Count=0;
		Score++;
	}
	if(Ground_cnt>=20)
	{
	Ground_cnt=0;//20ms地面 和 仙人掌一起移动
	Ground_Pos++;
	Barrier_Pos++;
		if(Ground_Pos>=256)Ground_Pos=0;
		if(Barrier_Pos>=144) Barrier_Pos=0;
	}
}

显示云朵 50ms移动一次 16x8 大小的云朵图像

uint8_t Cloud_Pos;
void Show_Cloud(void)
{
	OLED_ShowImage(127-Cloud_Pos,9,16,8,Cloud);
}

void Dino_Tick(void)
{
	//接上面程序

	if(Cloud_Count>=50)
	{  
		Cloud_Count=0;
		Cloud_Pos++;
		if(Cloud_Pos>=200)Cloud_Pos=0;
	}
}

画小恐龙,后脚着地,前脚着地,双脚着地的图片,取模软件取模

两种状态 奔跑 跳跃

奔跑:前后脚着地,每50ms切换一次

跳跃:就是Y坐标从小到大再到小

也就是sin函数 w=2*pi/T=2*pi/2*1s=pi

Y=28*sin(pi*t/1000)把s转化为ms

通过按键 1 触发跳跃(dino_jump_flag=1),利用正弦函数计算跳跃位移(Jump_Pos=28*sin(pi*jump_t/1000))模拟抛物线运动;奔跑状态下根据Cloud_Pos奇偶性切换两张恐龙图像实现跑步动画,跳跃时显示跳跃姿态图像;

//恐龙
extern uint8_t KeyNum;
uint16_t jump_t;	//跳跃计数
uint8_t dino_jump_flag=0;//0 奔跑 1 跳跃
uint8_t Jump_Pos;	//跳跃位移
extern double pi;

struct Object_Position dino;

void Show_Dino(void)
{
	KeyNum=Key_GetNum();
	if(KeyNum==1) dino_jump_flag=1;
	Jump_Pos=28*sin((float)(pi*jump_t/1000));
	if(dino_jump_flag==0)
	{
		if(Cloud_Pos%2==0) OLED_ShowImage(0,44,16,18,Dino[0]);
		else OLED_ShowImage(0,44,16,18,Dino[1]);
	}
	else
	{
	 OLED_ShowImage(0,44-Jump_Pos,16,18,Dino[2]);
	}
	dino.minX=0;
	dino.maxX=16;
	dino.minY=44-Jump_Pos;
	dino.maxY=62-Jump_Pos;
	
}

写个检测是否碰到障碍

  1. 定义碰撞边界
    为小恐龙和障碍物分别设定矩形碰撞框(通过struct Object_Position存储):

    • 小恐龙:dino.minX(左边界)、dino.maxX(右边界)、dino.minY(上边界)、dino.maxY(下边界)
    • 障碍物:barrier.minXbarrier.maxXbarrier.minYbarrier.maxY
  2. 判断坐标重叠
    当两个物体的矩形区域同时满足以下条件时,判定为碰撞:

    • 小恐龙的右边界 > 障碍物的左边界(dino.maxX > barrier.minX
    • 小恐龙的左边界 < 障碍物的右边界(dino.minX < barrier.maxX
    • 小恐龙的下边界 > 障碍物的上边界(dino.maxY > barrier.minY
    • 小恐龙的上边界 < 障碍物的下边界(dino.minY < barrier.maxY

void Show_Dino(void)
{
	//接上面的代码
	dino.minX=0;
	dino.maxX=16;
	dino.minY=44-Jump_Pos;
	dino.maxY=62-Jump_Pos;
	
}
void Show_Barrier(void)
{
	//接上面的代码
	barrier.minX=127-Barrier_Pos;
	barrier.maxX=127-Barrier_Pos+16;
	barrier.minY=44;
	barrier.maxY=44+18;

}
int isColliding(struct Object_Position *a,struct Object_Position *b)
{
	if((a->maxX>b->minX) && (a->minX<b->maxX) &&(a->maxY>b->minY) &&(a->minY<b->maxY))
	{
		OLED_Clear();
		OLED_ShowString(28,24,"Game Over",OLED_8X16);
		OLED_Update();
		Delay_s(1);
		OLED_Clear();
		OLED_Update();
		return 1;
	}
		return 0;
	
}