logo资料库

在STM32F103上编写一个俄罗斯方块游戏.pdf

第1页 / 共6页
第2页 / 共6页
第3页 / 共6页
第4页 / 共6页
第5页 / 共6页
第6页 / 共6页
资料共6页,全文预览结束
STM32F103 STM32F103 在 STM32F103 STM32F103 上编写一个俄罗斯方块游戏 我手边有一块 STM32F103VB 的板子,在这个板子上有一个 LCD 显示屏和 5 个按键, 正好可以用来做俄罗斯方块这个游戏。 图 1 STM32F103VB 开发板 我先是在这块板子上写了一个实时嵌入式操作系统内核——Mindows,当我完成了这个 操作系统的抢占式任务调度、信号量及队列等功能后,我想验证一下这个操作系统的功能, 于是,就在这块板子上写了一个俄罗斯方块的游戏,在此介绍一下这个游戏的设计思路,并 提供源代码,你可以在本文后面看到这个游戏在单板上运行的截图,如果你想观看游戏过程 的视频或获取源代码,请登录我的新浪博客 blog.sina.com.cn/ifreecoding 获取。 俄罗斯方块的游戏我们应该都玩过,先将这个游戏的基本功能整理一下。我们最容易想 到的是按键功能,需要能控制图形向下、向左和向右移动,还需要能旋转图形,当我们不按 向下按键时图形还需要能自动向下走,当游戏结束时,我们需要一个按键可以重新开始游戏。 在游戏过程中还需要遵守一些规则,比如说不同的图形互相之间不能重叠,图形不能移出屏 幕的范围,当屏幕的一行被图形填满时本行需要被删除,并且上面所有的图像向下移动,还 有最重要的一点,我们需要使用 LCD 将游戏的过程显示出来。 我们将这些需求做一个表格整理一下: 功能分类 子功能 描述 按键功能 界面功能 游戏功能 按下开始键,游戏重新开始,所有状态归零 按下旋转键,图形可以旋转 按下向下键,图形向下走 按下向左键,图形向左走 按下向右键,图形向右走 需要能实时显示游戏画面 开始键 旋转键 向下键 向左键 向右键 全屏显示 下个图形显示 将屏幕分为左右两部分,左侧为游戏空间,右侧显示下个出现的图形 自动走 冲突检测 下个图形开始 当图形向下走会发生冲突时对本图形的操作结束,下个图形从屏幕顶端 在没有按向下键时,图形应以一定速率自动向下走 当图形移动、变形时不能与其它图形重叠 进入屏幕,并更新屏幕右侧的下个图形
删除一行 删行闪烁 当图形向下走会发生冲突时对本图形的操作结束,检测是否有被图形占 满的一行,若有需要删除此行 在删除一行时,需要反复改变被删除行的颜色,以呈现出闪烁效果,然 后再删除此行 在一行被删除后,被删除行上面的所有图形都需要向下移一行 打印功能 图形下移 任务切换打印 将任务切换过程从串口打印出来 表 1 俄罗斯方块游戏需求列表 表 1 中列出了我们需要做的功能,接下来我们就要想办法来实现这些功能。我们首先要 解决的一个问题是我们必须要有一个办法能使用处理器来表示这些图形,这样才能对它们进 行控制,并将它们显示到 LCD 上。LCD 中的每一个像素就是一个数据,代表着这个像素的 颜色,因此我们可以在内存中用一个二维数组来对应 LCD 中的像素,数组的两个维度对应 着 LCD 的 X 轴和 Y 轴,数组中元素的数值就对应着 LCD 中对应位置的像素的数值,数组 元素为黑色像素的数值时代表 LCD 中对应的位置没有图形,其它数值代表有图形,这样就 可以把对 LCD 中图形的操作转换为对数组数据的操作了,然后再以一定的频率将数组中的 数据输出到 LCD 中,这样就实现用处理器控制 LCD 中的图形了。 经过上面的分析,我们就可以将图形映射为数组数据,我们只要专注于处理数组数据, 至于 LCD 中的图形则只需要将数组数据刷到 LCD 上就可以了。由此可以想到的一个简单的 处理方法是使用一个任务专门来处理数组数据,使用另一个任务专门来将数组数据刷 到 LCD 上,至于按键功能则可以用另一个任务专门来检测按键的输入。这样的 3 个任务相互 之间的耦合性很小,很适合使用并行的任务实现,按键任务负责检测按键输入,如有按键输 入则向处理数据的任务传送按键值,处理数据的任务接收到按键值就对数组数据进行处理, 而刷新 LCD 的任务只需要以固定的频率将数组数据刷新到 LCD 上就可以了。至于打印任务 切换的功能还可以使用 Mindows 提供的任务切换钩子函数的方法实现,在任务切换时使用 任务切换钩子函数将切换信息打印到内存中,再使用一个打印任务将内存中的数据打印到串 口。 按键、处理、刷屏这 3 个用于实现游戏功能的任务结构关系如下图所示: LCDLCDLCDLCD FlushScnTask 信 号 量 数组 数据 KeyTask 队列 ProcessTask 按键 图 2 俄罗斯方块游戏任务结构图 KeyTask 任务周而复始的检测按键是否按下,由于对按键按下的频率有要求,因此这个 任务需要以一定的间隔来读取按键值,在间隔期间内不读取按键值,这样也可以防止按键抖
动的情况发生。当该任务读取到一个有效的按键值时,就将这个按键值压入队列发送 给 ProcessTask 任务。 ProcessTask 任务周而复始的从队列里取消息,当队列为空时,该任务就会被队列阻塞, 处于 pend 状态,直到队列里有了消息才被激活,然后从队列里取出按键值,根据按键值来 对图形数组的数据做相应的操作。 FlushScn 任务则以一定的频率将图形数组中的数据刷新到 LCD 屏幕上。每个图形是由 多个像素组成的,对图形处理、刷新的过程就是对图形中像素的处理、刷新过程,需要对多 个像素进行多次操作才能完成对一个图形的操作。FlushScn 任务和 ProcessTask 任务是并行 执行的,为避免这两个任务在对同一个图形的处理过程中相互干扰,就需要在这 2 个任务中 使用信号量锁住对同一个图形的处理过程,使这两个任务对同一个图形的操作保持串行性, 保证图形处理、显示时的完整性。 这 3 个任务的结构大致如下所示: void TEST_KeyTask(void) { while(1) { /* 任务以一定的间隔读取按键值 */ MDS_TaskDelay(); /* 读取按键值 */ DEV_ReadKey(); /* 将按键值放入队列 */ MDS_QuePut(); } } void TEST_ProcessTask(void) { while(1) { /* 获取按键值 */ MDS_QueGet(); /* 获取信号量 */ MDS_SemTake(); /* 根据按键值对数组数据做相应处理 */ TEST_KeyProcess(); /* 释放信号量 */ MDS_SemGive(); } } void TEST_FlushScnTask(void) { while(1) { /* 获取信号量 */ MDS_SemTake(); /* 刷新 LCD 屏幕 */ TEST_FlushScn();
/* 释放信号量 */ MDS_SemGive(); /* 任务以一定的间隔刷新 LCD */ MDS_TaskDelay(); } } KeyTask 任 务 和 FlushScn 任 务 比 较 简 单 , 都 是 以 固 定 的 频 率 执 行 重 复 的 动 作 , ProcessTask 任务比较复杂,是实现俄罗斯方块游戏的关键,下面我们再重点介绍一下这个 任务。 ProcessTask 任务的主要功能是根据按键值来对数组数据做相应的处理,这其中涉及到 图形移动、变形、冲突检测、删除等操作,实现了这些操作也就基本实现了俄罗斯方块这个 游戏。 俄罗斯方块游戏里共有 8 种基本的图形,部分图形经过旋转会表现出不同的形状,如下 图所示: 图 3 俄罗斯方块游戏图形 这些图形都是由基本的小方块组成,每个小方块都是由 4×4 的像素组成,每次对图形 处理都是以这些小方块为基本单元进行的,因此,我们可以将每个小方块看做是一个像素, 这样就可以使用较少的内存来映射整个 LCD 的屏幕了。 STM32F103VB 板子上 LCD 的大小为 128×160 像素,每个像素需要用 16bits 数据来表 示它的颜色。这其中我们使用左边的 88×160 像素作为游戏区域,右边 36×160 像素作为下 个图形显示区域,中间用 4×160 像素的线条作为左右部分的分隔线。左边游戏区域内的图 形会不断的发生变化,因此我们需要使用一个(88÷4)×(128÷4)大小的 short 型二维数组来 表示游戏区域。中间分隔线不会变化,只需要在初始化时画出这条线就可以了,不需要在内 存中保留相应的数组。右侧的下个图形显示区只是更新下个图像这一小块区域就可以了。 这些图形中最长的图形长度为 5×4=20 个像素,考虑到变形,我们需要使用 20×20 个 像素的一块空间才能存放下任意一个图形,因此,我们只需要在内存中开辟一个(20÷4)×(20 ÷4)大小的 short 型二维数组就可以表示任意一个图形了,更新屏幕右侧的下一个图形窗口 只需要这么大小的一块内存就可以了。 当图形在游戏区域内向下移动的时候,我们还需要开辟一个(20÷4)×(20÷4)大小的 short 型二维数组来表示当前的图形,当图形向下走一行时,先从游戏区域数组里将该图形 清除掉,然后将当前图形数组在游戏区域数组内下移一行,如果下移后的当前图形数组与游
戏区域数组没有图形数据冲突的话,就将下移后的当前图形数组写入游戏区域数组内,完成 本次下移操作。如果有冲突的话,则说明当前图形已经不能再下移动了,将当前图形数组原 地恢复到游戏区域数组内,再去判断当前图形所在的所有行内是否有填充满的整行数据,如 果有的话就删除这些行,在删除的时候每隔一段时间变换一下这些行的颜色,以表现出删行 时闪烁的效果。当删除一行后,需要将该行上面的所有图形数据都向下移动一行,并将下个 图像数组复制到当前图形数组内,将当前数组的位置恢复到图形出现的最上方,再随机选择 一个图形,将下个图形数组更新为该图形,完成本次操作。 其它的向左向右和变形操作也需要先从游戏区域数组内将当前图形清除掉,然后判断相 应操作后是否会有图形冲突,如果没有冲突的话就将当前图形数组数据复制到操作后所在的 游戏区域数组内的位置,完成本次操作,如果有冲突的话就将当前图形数组原地恢复到游戏 区域数组内,结束本次操作。 上面就是有关俄罗斯方块游戏的基本介绍,代码就不具体介绍了,代码里都有注释,通 过本文的介绍并结合代码应该就可以理解这个游戏的实现方法了。如果你感兴趣的话,可以 再增加一个按键声音的功能,无非就是再创建一个播放声音的任务,当按键任务检测到按键 时向声音任务发送一个消息激活声音任务,由声音任务播放按键声音,原来的软件结构基本 不用改动。 下图是在 STM32F103VB 单板上运行俄罗斯方块的图片,如果你想观看游戏视频或者查 看源代码的话请登录我的博客 blog.sina.com.cn/ifreecoding 下载。
图 4 STM32F103VB 单板运行俄罗斯方块游戏
分享到:
收藏