这篇文章主要是代码分享,俄罗斯方块的游戏功能代码部分以及简单解析。
对代码哪里不理解的,欢迎找我讨论哈。
和上篇代码结构不一样的地方是多文件和分模块,使得工程更加有条理。
本意是直接抛代码的,没想到啰里啰唆搞了一大堆。
目录
俄罗斯方块总体设计
为什么第三篇和其他不一样呢?很显然这块是这个小项目的核心嘛,单片机是个专用的计算机系统,在这个项目里就体现在这里了。因为你所有的设计都是围绕着这个目标来的,甚至于可能要推到重来。
一、游戏规则
我们大多数人就算没有玩过,也应该听说过这个游戏,不然你也搜不到这个文章。这里我们以自己观察到的游戏现象,简单的例举几条规则。
1.游戏中,图形自上而下以恒定的速度下落
我觉得,这条规则,进入游戏,不需要任何操作,立马就能观察到,但可能不以为然。3秒之后你就可能认为不重要了,但是你不能忘记这个时候你的角色不是玩家,你是要自己写出来这个游戏的。单片机所有的现象都是出自于你的程序,如果出现了你预料之外的情况,那就是你作为开发者考虑不周,丢掉这些情况的处理,这就要求,你要尽可能多的制定规则,多熟悉规则,当你完整的做完一个小游戏,你就能体会到什么叫无规矩不成方圆,规则之内你是自由的。
那么你是不是应该能想到,他是不是应该有个限制,这就引出了第二条规则。
2.游戏中,图形运动范围是有限的,且是变化的
我觉得,你立马能想到的是速度,是恒定的。接着是下落是由范围的,接触到底边就不动了。然后顶部会出现新的图形,继续下落,当碰到上一个已经不动的图形后,新图形也就不动了,再在顶部出现一个新图形继续开始下落。
3.游戏结束的触发条件
直至最新的图新出现后立马就碰到了上一个图形,游戏就结束了。
以上观察到的规则都是基于你没有任何操作。
如果这个时候你的小手手那么轻轻的一抖,碰到了按键,恭喜你发现新大陆了。
4.游戏中,图形左右运动范围是也有限的
假设你碰到的是左右移按键,你绝对会发现,下落过程中的图形是可以左右移动的,且两边都是有边界的。碰到之后就不能往这个方向移动了。然后你在看看按键,这才两个,另外的可能是什么效果。
5.游戏中,移动的图形是可以旋转的
假设你碰到的是图形变换按键,下落过程中的图形就会旋转,实际上是每次90°,但部分图形,旋转180°还是原来的样子,有的干脆怎么旋转都是原来的样子,没有什么变化。
6.游戏中,移动的图形是可以加速下落的
假设你碰到的是加速键,你就会敏锐的发现,下落过程中的图形,嗖就下来了。说明速度在这个时候变大了,但是是另一个很定值。当你松开加速按键的时候,速度就恢复到原来的速度了。
7.游戏中,每集满一行,这一行是可以消除掉的,并且上边累积的图形可以向下落,补上这一行
正常情况下我们能观察到的游戏规则就多这么多了。
如果从来没有做过复盘的人,是不是被震惊到了,没想到一个简单的小游戏竟然这么多规则。
所以说没有哪个东西是容易的,都是需要花心思的。
二、游戏中的小功能实现
了解了上述规则,浅玩一下这个小游戏肯定是够了,但是离动手做出来还是有点距离的。
到目前为止,我们已经有独立按键的输入检测和屏幕的输出驱动。
但是屏幕输出驱动提供的接口只提供了像素点的读写,总是感觉哪里不对,是滴,你得感觉没有错。
这篇文章到这里位置,从来没有提过每个图形的组成。
1.画小方块的函数实现
你仔细观察就会发现,每个图形都是由小方块组成的。每个小方块都是由像素点组成的。
聪明的你立马就能想到,我需要一个函数能画小方块。
这个时候就会和显示硬件打交道了,我们这次用的显示屏LCD12864,每个像素点该怎么控制显示。这个屏幕呢是个单色屏,也就是一个像素点只能显示两种状态,亮和灭,似乎有一丝丝熟悉的味道,没错就是led灯。那就是说,我只要告诉显示屏你把我需要的像素点亮和关闭就可以了。那问题来了,这里边你需要的哪个像素点怎么描述,我想行你瞬间就能想到坐标这两个字。这个时候画小方块的函数呼之欲出了,有没有。那还有几个问题,每个小方块该画多大,样式是什么样的,还能让人一眼就看出来每个小方块边界。我们的屏幕规格是长边是128个像素点,短边是64个像素点,所以方块不能太大,那就每个方块占4X4个像素点,为了能一眼就分辨出,再留个边,显示部分3X3,中间空一个像素点。
void Game_SquareDraw(Game_PointTypedef P,uint8_t Value)
{
Value &= 0x01;
Game_PointTypedef p = {
P.x << 2,P.y << 2};
LCD_Pixel_Write(p.x + 0,p.y + 0,Value);
LCD_Pixel_Write(p.x + 1,p.y + 0,Value);
LCD_Pixel_Write(p.x + 2,p.y + 0,Value);
LCD_Pixel_Write(p.x + 0,p.y + 1,Value);
//LCD_Pixel_Write(p.x + 1,p.y + 1,0);
LCD_Pixel_Write(p.x + 2,p.y + 1,Value);
LCD_Pixel_Write(p.x + 0,p.y + 2,Value);
LCD_Pixel_Write(p.x + 1,p.y + 2,Value);
LCD_Pixel_Write(p.x + 2,p.y + 2,Value);
}
2.屏幕坐标描述
那你就会说,这多简单啊,坐标嘛,不就是x,y吗,我在数学书上学过这个,这有什么值得说道的。没错没错,这个确实简单,数学中常常是这么用x轴向右,y轴向上。x和y就可以确定平面里的所有坐标了,当然屏幕里也是x和有,只是需要注意的是,大家公认的都是左上角为原点(0,0),向右为x的正方向,向下为y的正方向,包括windows图形界面开发中也是这样。
这样的话抛个描述坐标的结构体不过分吧。
typedef struct
{
int8_t x;
int8_t y;
}Game_PointTypedef;
3.图形的组成描述
小方块可以画了,接下来肯定是画图形了嘛,所以我们需要观察这个游戏,你会发现一共7种图形,每个图形由四个小方块组成。那我们应该把这图形组织起来,那就的来个结构体了。每个小方块形状是固定的,那我们就可以用一个坐标代替一个小方块,这样一个坐标就可以由四个坐标组成。
typedef struct
{
Game_PointTypedef p[4];
}Game_PicTypedef;
4.图形的枚举
好了,图形并不是凭空产生的,这种情况下我们就需要把我们所需要的所有图形枚举出来。C语言关键字const,在单片机的世界里一般认为是保存在flash中,使用的时候也是直接从flash中读取,不可在运行过程中修改。为什么说是一般认为呢?