PWM硬件移相测试卡教程(二)贪吃蛇@STC8H2K12U系列
话不多说,先上测试视频:118
这一章节用的硬件是PWM移相测试卡+OLED12864 ( SSD1306_IIC)
序言、
最近刷抖音看到了个贪吃蛇,这不一下就激起了童年的回忆,准备小试牛刀做个贪吃蛇耍耍。既然也做出来了个初版,那就给广大网友一起耍耍了,想自己借鉴或者升级的也可以仔细看下文章,想玩的直接群文件下载代码即可。这个帖子的代码用的最最好理解的方法写的,适合新手练习,老鸟略过哈哈。
一、知识储备
1.去下面这个帖子学习IIC的知识:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=236
2.去下面这个帖子学习OLED显示汉字的知识:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=30
3.去下面的帖子学习单片机驱动G驱动OLED12864,I2C方式:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=2592
4.去下面的帖子学习菜单:https://www.stcaimcu.com/forum.php?mod=viewthread&tid=44
二、效果分析
按键,oled初始化什么的比较简单就略过了,有需要的可以去看上面的帖子。这里主要讲绘图和蛇的动作。
1.界面功能切换的结构体
typedef struct Menu
{
uint8_t Sub;
//进入下一级
uint8_t Enter;
//返回上一级
uint8_t Back;
// 对应的函数指针
void (*Current_Operation)(void);
} Menu_Table;
程序里基于这个结构体定义了一个结构体数组,
Menu_Table Table= { /* 菜单及界面 */
/*SUB EBF */
{2, 1, 0, Menu},
{0, 1, 0, Game},
{0, 0, 0, GameMode}
};
这个结构体数组讲用到的三个界面都做进去了,分别是主菜单界面(Menu),游戏界面(Game),游戏模式设置界面(GameMode)。
2.界面和功能切换的函数指针
在代码里定义了一个 void (*Operation)(void); 的函数指针,Operation指向要执行的函数。Operation=Table.Current_Operation指向当前界面的函数,然后再主循环里不断的循环执行这个函数。这部分不懂得可以去参考上面的菜单的帖子。
3.主菜单界面(Menu)介绍
(1)如果切换过界面,先清除当前界面的显示
(2)初始化所有的运行变量
(3)显示汉字
(4)判断当前的模式并在指定位置显示 *
具体的实现代码如下:
void Menu(void)
{
if(modeFlag)
{
OLED_Clear();
}
/* 不在游戏中 */
playing = 0;
modeFlag = 0;
replay = 1;
Get_Command();
/* 关闭定时器 */
TR0 = 0;
/* 显示贪吃蛇 */
OLED_ShowCHinese(44,0,0);
OLED_ShowCHinese(60,0,1);
OLED_ShowCHinese(76,0,2);
/* 开始游戏 */
OLED_ShowCHinese(34,3,3);
OLED_ShowCHinese(50,3,4);
OLED_ShowCHinese(66,3,5);
OLED_ShowCHinese(82,3,6);
/* 难度选择 */
OLED_ShowCHinese(34,5,7);
OLED_ShowCHinese(50,5,8);
OLED_ShowCHinese(66,5,9);
OLED_ShowCHinese(82,5,10);
/* 菜单选择 */
switch(menuSelect)
{
case MAINMENU:
OLED_ShowChar(14,3,'*',16);
OLED_ShowChar(14,5,' ',16);
break;
case GAMEMODE:
OLED_ShowChar(14,5,'*',16);
OLED_ShowChar(14,3,' ',16);
break;
}
}
显示效果图如下图所示:
4.游戏模式设置界面(GameMode)
(1)如果切换过界面,先清除当前界面的显示
(2)初始化所有的运行变量
(3)显示汉字
(4)判断当前的模式并在指定位置显示 * ,表示当前选中
具体的实现代码如下:
void GameMode(void)
{
if(!modeFlag)
{
OLED_Clear();
}
Get_Command();
playing = 0;
modeFlag = 1;
OLED_ShowCHinese(34,1,15);
OLED_ShowCHinese(50,1,16);
OLED_ShowCHinese(34,4,17);
OLED_ShowCHinese(50,4,18);
switch(CuMode)
{
case 0:
OLED_ShowChar(14,1,'*',16);
OLED_ShowChar(14,4,' ',16);
break;
case 1:
OLED_ShowChar(14,1,' ',16);
OLED_ShowChar(14,4,'*',16);
break;
}
}显示效果图如下图所示:
5.游戏界面(Game)
(1)是否重新开界面,先清除当前界面的显示和之前的游戏记录
(2)定时时间到了蛇移动,如果移动后吃到了食物在重新生成,画新的蛇
(3)如果游戏结束了展示成绩
具体的实现代码如下:
void Game(void)
{
/* 重开游戏 */
if(replay)
{
/* 贪吃蛇初始化 */
clearSnake();
GUI_Init();
replay = 0;
}
/* 正在游戏中 */
playing = 1;
/* 开启定时器 */
TR0 = 1;
if(timerFlag)
{
Move();
Eat_Food();
drawSnake();
timerFlag = 0;
}
//定时器0开始计时
Get_Command();
GUI_Refresh(map);
if(GameOver())
{
OLED_Clear();
/* 展示成绩 */
Show_Score();
Delay2000ms();
OLED_Clear();
Cur = Table.Back;
}
}显示效果图如下图所示:
三、蛇体部分分析
1.如何实现游戏界面的显示:本项目使用的OLED屏是0.96寸的,像素为128*64。贪吃蛇少不了蛇,如果采用一个像素点来画蛇的身体,那这个蛇小到离谱,不够明显。所以本项目使用的4*4像素的正方形(只点亮外框像素)来绘制蛇的身体。实现的思路大致如下:使用map 放大四倍变为128*64。
map : 对应的是上图中的左边。用于存储数据,然后调用GUI_Refresh判断相应的值,做出对应的操作,然后放大四倍成为上图中的右边,最后再调用OLED里面的相关代码,就会把数据写入OLED_GRAM。例如:void Paint_Body(uint8_t x,uint8_t y )//绘制身体
{
uint8_t i,j;
for(i=4*y; i<4*y+4; i++)
{
for(j=4*x; j<4*x+4; j++)
{
if(i==4*y||i==4*y+3)
{
OLED_DrawPoint(j,i);
}
if(j==4*x||j==4*x+3)
{
OLED_DrawPoint(j,i);
}
}
}
}
void Paint这里OLED_GRAM:作为OLED的显存数组,通过这个数据就可以让OLED上对应的像素亮起来。• snake_Grid: 用来存储蛇的坐标,后面会有讲解。其他的代码也可以这样实现,比如画外框,食物等。之后就只需要操作map数组,就可以完成我们的贪吃蛇啦。
2.游戏规则设计上面有提到snake_Grid是用于存储蛇的坐标的,同时snake_Grid和snake_Grid是来存储蛇头的坐标,我们只需要判断蛇的其他坐标是不是等于蛇头的坐标,相等说明吃到自己了,结束游戏;另一个规则是撞到墙游戏结束,只需要判断蛇头的坐标是不是等于0xfe(0xfe对应的是边框值)。 // 撞到墙结束游戏
if(map]] == 0xfe && GameDifficulty==1)
{
// crashWall
crashWall = 1;
}bit GameOver(void)
{
//蛇头坐标
uint8_t sx=snake_Grid,sy=snake_Grid,i;
//判断有没有吃到自己
for(i=1; i<length; i++)
{
if(snake_Grid==sx && snake_Grid==sy)
return 1;
}
//如果撞到墙
if(crashWall==1 && GameDifficulty==1)
{
crashWall = 0;
return 1;
}
return 0;
}
具体的代码都在上面讲解了,有需要源码的小伙伴可以在群文件下载,有任何问题可以在下面留言!
有奖征集,谁能第一个把这个代码里的显示屏的显示改为字库索引的方式的话
(附上修改好的代码,并展示用STC-ISP软件实现汉字取模的过程方为有效),
免费送一套这个文中的硬件!注意:只有在本文下方第一个发布的才有效!!
收藏 再看,不会搞字模{:4_184:}
PWM硬件移相测试卡教程(四)组合PWM(180度移相互补输出)@STC8H2K12U系列
PWM硬件移相测试卡教程(四)组合PWM(180度移相互补输出)@STC8H2K12U系列 - 工控板,PLC,STC8/STC32实现 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
PWM硬件移相测试卡教程(三)不对称PWM(高速正交编码信号输出)@STC
PWM硬件移相测试卡教程(三)不对称PWM(高速正交编码信号输出)@STC - 工控板,PLC,STC8/STC32实现 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
PWM硬件移相测试卡教程(二)贪吃蛇@STC8H2K12U系列
PWM硬件移相测试卡教程(二)贪吃蛇@STC8H2K12U系列 - 工控板,PLC,STC8/STC32实现 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
PWM硬件移相测试卡教程(一)按键点灯测试@STC8H2K12U系列
PWM硬件移相测试卡教程(一)按键点灯测试@STC8H2K12U系列 - 工控板,PLC,STC8/STC32实现 - 国芯论坛-STC全球32位8051爱好者互助交流社区 - STC全球32位8051爱好者互助交流社区 (stcaimcu.com)
本帖最后由 四汐 于 2024-4-9 18:48 编辑
修改前:
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no)
{
u8 t,adder=0;
OLED_Set_Pos(x,y);
for(t=0; t<16; t++)
{
OLED_WR_Byte(Hzk,OLED_DATA);
adder+=1;
}
OLED_Set_Pos(x,y+1);
for(t=0; t<16; t++)
{
OLED_WR_Byte(Hzk,OLED_DATA);
adder+=1;
}
}
修改后:
取模设置:
字库:
四汐 发表于 2024-4-9 18:45
修改前:
附上改完之后的代码压缩包即可领取哈{:lol:} 没入群就没源码下了? 电子DIY小家 发表于 2024-4-9 21:27
附上改完之后的代码压缩包即可领取哈
四汐 发表于 2024-4-11 01:13
{:5_272:}q群里私聊下群主领取奖励 还是放个附件,完整程序,供大家方便下载,
体现我们纯技术论坛的博大精深
神农鼎 发表于 2024-4-11 08:19
还是放个附件,完整程序,供大家方便下载,
体现我们纯技术论坛的博大精深
...
上面有群友放了升级版的代码{:5_332:}
页:
[1]
2