智能手表:小恐龙游戏

小恐龙

初始菜单下 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;
	
}
相关推荐
谷宇.37 分钟前
【Unity3D实例-功能-镜头】第三人称视觉
游戏·unity·unity3d·游戏开发·游戏编程·steam
白仑色2 小时前
JavaScript案例(乘法答题游戏)
开发语言·javascript·游戏
亚马逊云开发者4 小时前
零代码生成 3D 游戏:基于 Amazon Q Developer CLI 和 Three.js 的实践
人工智能·游戏
深海潜水员17 小时前
【Unity】背包系统 + 物品管理窗口 (上)
开发语言·vscode·游戏·unity·c#·游戏引擎
伽蓝_游戏17 小时前
Unity UI的未来之路:从UGUI到UI Toolkit的架构演进与特性剖析(6)
游戏·ui·unity·架构·c#·游戏引擎·.net
小梦白21 小时前
RPG增容3:尝试使用MVC结构搭建玩家升级UI(一)
游戏·ui·ue5·mvc
终端域名1 天前
元宇宙三维化会给游戏行业带来哪些改变?
游戏·元宇宙
小梦白2 天前
RPG增容2.尝试使用MMC根据游戏难度自定义更改怪物属性(三)
游戏
向宇it2 天前
【unity实战】简易的车辆控制系统
游戏·unity·c#·游戏引擎