2021暑假一起练-用树莓派 pico 移植经典游戏--贪吃蛇
2021暑假一起练-用树莓派 pico 移植经典游戏--贪吃蛇
标签
树莓派
嵌入式系统
贪吃蛇
游戏
shayebuhui
更新2021-09-10
1985

一、 项目要求

  1. 设计或移植一款经典的游戏,通过LCD屏显示,通过按键和旋转编码器控制
  2. 在游戏中要通过蜂鸣器播放背景音乐

二、设计思路 (一)总体思路

完成贪吃蛇这个游戏所需实现的基础功能有:

  1. 初始蛇头位置及食物的随机生成。
  2. 蛇随玩家按键控制进行移动。
  3. 蛇吃到食物后长度增加。
  4. 蛇碰到边界或者自己的身体时游戏结束。
  5. 游戏进行过程中播放bgm。

同时为了整个游戏的完整性和提高可玩性,增加的额外功能有:

  1. 游戏开始界面及结束界面。
  2. 实时显示所得分数及游戏难度。
  3. 随着游戏得分增多,游戏难度逐级上升。

整个设计的重点在于对开发板上这块st7789 240*240的LCD屏幕进行显示控制,正好有漂移菌所改写的st7789.py库函数能够帮助我完成这些要求,因此我选择与其程序语言相匹配的micropython进行开发。

还有一个贯穿游戏始终的蛇的变化,玩家控制方向键吃到食物,蛇身的坐标都在不断变化,这些坐标都需要及时的保存及反馈给其他模块,因此我将蛇的坐标保存在列表当中,以便随时修改。

大致游戏流程图如下:

Fmco5N4PIYi8aJTU_vq2LIKigu98

(二)设计过程

1、初始蛇头位置及食物的随机生成模块

我利用random.randrange(x,y)函数实现初始蛇头位置及食物随机坐标的生成,但是为了设计的便捷,我希望蛇吃到食物时能与食物完全重合。因此我将生成的随机坐标进行数学处理,去除坐标的个位,保证生成的坐标都是十的倍数,这样不管蛇从哪个方向过来都能与食物完全重合。


还有一个问题就是食物不能生成在蛇身所覆盖的范围内,否则游戏将无法进行下去。因此我将保存了蛇身上所有坐标的列表实时传送给生成坐标的函数进行判断,如果生成的坐标在蛇身所覆盖的范围内,就重新生成。至此就能保证随机生成的坐标不会出错。

流程框图

FhnkFsdmffSBk3kIc-osWQAPBo7n

对应代码及解释

Fh4GnFWeCb2mMT5MebMpYhG3tbGT 2、贪吃蛇的按键控制

开发板上只有两个按键,但是控制蛇上下左右移动需要四个按键,考虑到玩家游玩的便捷性,我将板上的旋转编码器作为控制贪吃蛇左右移动的工具,原有的两个按键作为上下控制。

旋转编码器的A脚和B在在顺时针和逆时针旋转时会产生不同次序的方波,如图:

Fs_8R7CcDOIU88-lxEMh1HTJYvtI

(顺时针)

FkLbjFg_ktl5pNMByHUf90bfurcK

(逆时针)

通过判断A在上升沿和下降沿时B的电位高低就可以判断旋转方向,我设定逆时针为左转,顺时针为右转,这样贪吃蛇的控制方式就定下了。为了保证按键和旋转的灵敏,所有的控制方式我都采用外部中断,按下按键或旋转编码器都会进入中断,判断后设置各自标志位,在控制蛇行动的程序中加以判断产生对应反应,经过测试效果不错。

经过测试,开发板上的旋转编码器是两定位一脉冲的,即转一格A脚输出半个周期的脉冲,转两个输出一个完整周期的脉冲,所以在程序中我对A脚的上升沿和下降沿分别判断,提高识别的准确度。

Fj9-oKcfWS-CfpkGjNboMQVNyC8sFqbd-N1KO2JL5P6SlddBhRwCbzrpFnHNHXBuI6j-4_58SwyvieuvbsLfFnBd8k3QFwpU_REWVQ6g16k3Q6a6

3、贪吃蛇的移动及成长

蛇在移动过程中并不是身上所有坐标都在变,只需要把新的头坐标加在列表的首位,同时将尾部坐标即列表的最后一组坐标删去就可以得到新的蛇身列表。同样,当蛇吃到食物时,按照行进方向在头坐标前添加适当的坐标即可。

FvS1CDkzgNPLpVICbCvcuADR-H2WFrj_g29oXSDl4R4CuI36cDtivu71FheRD8p79MSlkuaJ4nqTZq-rzWO9

游戏中玩家按下一次按键后,如果没有按下其他键,蛇应该朝着最后一次按下的方向一直前行,所以要设置一个循环,当没有按键被按下时按照最后一次按键设定的方向生成新的列表并显示。

FguMBi8wb24jPW0jdnBrVCeh9OHE

4、游戏结束的判定

游戏中如果蛇碰到了墙壁或者自己的身体,游戏应当结束。因此我设置了边界范围实时比较,同时将蛇头坐标与蛇身列表依次比较,但是要保证X坐标与Y坐标一一对应,否则判断会出错。若蛇头的X坐标与Y坐标存在于蛇身列表中,说明发生碰撞,游戏结束。Fo6tE8oqwkDXjigf7WK0iCuQXRJr

5、在游戏中用蜂鸣器播放bgm

通过控制蜂鸣器引脚上方波的频率可以控制蜂鸣器发声的音调,控制方波的占空比可以控制蜂鸣器发声的声音大小。而Micropython利用函数可以非常方便地在引脚上输出PWM波,只要将音调对应的频率和每个音的长度写入列表,用循环语句便可让蜂鸣器奏乐。为了不让游戏本体和蜂鸣器音乐互相冲突,我将音乐部分写入定时器中断,每次进入中断按照音调列表中的顺序依次产生不同频率的PWM波,然后通过音长列表给中断定时的时间赋值,即用等待中断的时间用来让蜂鸣器发出规定时间的声音。这样就避免了用传统delay的方式让蜂鸣器发出规定时间的声音而占用游戏本体运行时间导致二者冲突。这样基本可以实现播放音乐的同时游戏的进程也不会受到影响。Fmx8geHYhEAqwCfz8z6y2148wWgk

6、根据游戏得分调整游戏难度

贪吃蛇每吃下一个食物游戏得分加一,我在每次贪吃蛇移动之后通过设定延时时间来控制贪吃蛇移动的速度,得分增加到5分、10分、15分、20分之后,延时时间都会缩短,以加快速度。FuBRDCGTD_LEZY5jVbcondfPhSfs

7、   游戏界面及得分栏设计

FunExobrhtBUvVcnpOsmcNn2vXgdFvqsHFKpEmY-uftX7fcDDftfSnVtFvoWSTcBrORSO0aE51R73mcdEUTaFpXIWZ4CX97QBYVCq5Cqg-iIku-iFn1voMuOHiwQYiekPGqw58K_wFP6Fhp6bz-ru-4G6Ns1B2MveG3u75-c

三、设计中的问题

  • 在使用旋转编码器作为控制左右的过程中,我发现如果只是简单的判断进入中断时B脚的电位高低,最终游戏中呈现的效果并不好,方向很容易误判,我猜测是因为旋转过程中机械部分有扰动造成的,为此我对那一部分函数做了很多防干扰处理,比如进入中断时同时也检测A脚的电平,判断是否是因干扰才进入中断;对进入中断后产生判断的次数进行计数,达到一个比较合适的值才认为结果有效并输出,消除偶然干扰的影响。经过处理,误判的情况已经基本不会出现。但是游戏中一直旋转编码器,有时程序会异常停止,也无法通过ctrl+c强制退出,目前这一点我还不清楚缘由,尚未解决。
  • 还有一个困扰了我很久的问题就是如何在进行游戏的同时能够流畅的播放BGM,我原来播放音乐的方案是通过delay函数控制每个音符持续的时间,但是游戏部分有自己的循环和时序,在其中穿插BGM会导致蜂鸣器播放时进入延时,游戏暂停,同时播放音乐每个音符的长度都是严格规定的,时间不对整首歌听起来就会显得不着调。就算使用双线程也无济于事,因此最后我决定放弃用delay函数作为控制音长的方式,改为控制定时器的时间,问题很好的得到了解决。

四、作品最终实现功能

1、玩家通过两个按键控制贪吃蛇上下移动,通过旋转编码器控制左右,贪吃蛇吃到食物身体长度增加,累计一定分数蛇移动速度加快,当蛇碰到自己身体或碰到边界时游戏结束。

2、游戏中会播放《欢乐颂》作为背景音乐,游戏结束通过板上run键重新开始。

五、心得总结

这次活动对我来说是一次全新的挑战,因为对嵌入式感兴趣,又觉得树莓派这个名字很好玩所以就选择这个项目,但是对我来说完成这项目并不轻松,在学校我只有学习过用汇编语言51单片机的经验,其他也就学过C语言,拿到这个板子之后也是摸索了很久,因为网上基本都是用mircopython控制树莓派的,所以尽管我没有接触过python,我还是选择用mircopython作为我的书写语言。这段时间的努力毫无疑问让我自己的能力得到了提升,查阅资料、自学语言、修改bug等等等等,这些都将成为我的宝贵经验,日后有机会我还会继续参加此类活动,锻炼自己的能力。

附件下载
贪吃蛇.py
主程序
st7789.py
控制屏幕的库函数
团队介绍
安徽师范大学19级电子信息工程
团队成员
shayebuhui
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号