自己动手写俄罗斯方块(一)

来源:互联网 发布:python idle3.5.2 编辑:程序博客网 时间:2024/04/28 15:43

思路整理

 1 设定方块的大小及游戏区坐标

  设定好方块的固定大小,及游戏去的开始坐标。

 2 建立游戏区:

 根据刚才设定的坐标建立一个2010列的一个游戏区,每行每列交叉处构成的方格即为一个方块的大小。这里我们需要弄清楚的就是游戏区的坐标。它不同于系统默认坐标。我们将游戏去左上角的坐标定位(00)。则此时游戏去左下角的坐标就是(020)了。而不是(019),但我们使用的时候使用到(019)就OK了。这个须明白。

 3 初始化俄罗斯方块的7中图形

 我们都知道俄罗斯方块有7中图形,分别为:

 SZLJIOT 这几个字母的形状。每种图形又经过四个方向的旋转又可以得到四种图形(有的是2种或1种)。这些图形我们不可能在游戏中随时画,只能做一个初始化,在游戏时用到时,就调用我们初始化的内容将方块画出来。

这个我们可以把它交给一个POINT类型三维数组来实现。如:我们可以定义一个这样的三维数组:

const POINT Terics[7][4][4] =

{

  {

      0,0,1,0,0,1,-1,1,

      0,0,0,1,1,1,1,2,

      0,0,1,0,0,1,-1,1,

      0,0,0,1,1,1,1,2

  },

  {

      0,0,1,0,1,1,2,1,

      0,0,0,1,-1,1,-1,2,

      0,0,1,0,1,1,2,1,

      0,0,0,1,-1,1,-1,2

  },

  {

      0,0,0,1,0,2,1,2,

      0,0,0,1,-1,1,-2,1,

      0,0,1,0,1,1,1,2,

      0,0,0,1,1,0,2,0

  },

  {

      0,0,0,1,0,2,-1,2,

      0,0,1,0,2,0,2,1,

      0,0,1,0,0,1,0,2,

      0,0,0,1,1,1,2,1

  },

  {

      0,0,0,1,0,2,0,3,

      0,0,1,0,2,0,3,0,

      0,0,0,1,0,2,0,3,

      0,0,1,0,2,0,3,0

  },

  {

      0,0,1,0,0,1,1,1,

      0,0,1,0,0,1,1,1,

      0,0,1,0,0,1,1,1,

      0,0,1,0,0,1,1,1

  },

  {

      0,0,1,0,2,0,1,1,

      0,0,0,1,0,2,1,1,

      0,0,0,1,-1,1,1,1,

      0,0,0,1,0,2,-1,1

  }

};  

首先从大的来说第一个维数7表示7中图形,第二个维数4表示4个方向,第三个维数表示4point型的数。

通过这个三维数组我们就可以根据当前坐标来加上我们初始化的数组就可以得出每个图形四个方块的左上角坐标,就可以在当前位置画出各种各样的图形了。注意:这个三维数组的初始化没有定数,有很多方法。

4 游戏按键

  我们只需用到上下左右四个按键即可,变形上键,加速下键,左右表示左右移动。这里需要注意的是。我们每次移动的就是一个方块的距离。

每用户点击游戏开始时便开始从上往下落方块,用户不按任何键时,方块自动正常下落。这个工作可以交给SetTimer来控制,我们可以在WM_CREATE消息中SetTimer(hwnd,1,1000,NULL);

然后就可以在WM_TIEMR中通过改变图形的纵坐标来实现方块下移。

若用户按:

左键:向左移动一个位置。通过减少横坐标来实现。

右键:向右移动一个位置。通过增加横坐标来实现。

上键:有规律的变换方向,即四个方向依次变换。通过改变方向

来实现。

下键:加速下移。通过,增加纵坐标来实现。

上述的四个游戏按键,我们可以在WM_KEYDOWN消息里去实

现,当窗口函数获得WM_KEYDOWN消息时。它的第三个参数

wParam保存的将是按键的更详细的内容。我们可以通过一个switch…case循环来查找我们想要的消息。

左键 VK_LEFT 右键 VK_RIGHT 上键 VK_UP 下键

VK_DOWN

5 判断范围

每次用户按下键后都要进行判断是否超出了范围,若超出范围不响应

用户的按键。

判断方式:根据用户当前的坐标去计算出该形状的四个方块每个坐

标,然后去判断是否超出我们的游戏区,并且还用判断将要要移

动向的区域是否已经有方块了。若有或超出范围均表示用户按键的条

件不成立,均不予响应。更详细的在第6步中有详细说明。

6 保存游戏区当前的状态

我们需要保存游戏区当前的状态,一个是为了第5步的判断用,另一

个也是为了我们的窗口刷新时加载已存在的方块用。

保存状态的方式:我们可以定义一个整型二维数组来保存,可想而知

这个二维数组的横纵坐标当然应该是游戏区的棋盘的行数和列数

啦。。也就是游戏区的坐标。如我们可以定义这样一个二维数组:

int GameMap[20][10] = {0};2010列。初始化为0

我们应该何时来保存当前的状态呢?

当然是在我们的方块落到最低端或是遇到方块时不能再自动往下移

动的时候了。注意这里的自动。只要不超出范围或不碰到方块,即方

块可以自动的下移的时候,我们都不应该去保存游戏区的状态。因此

时游戏区的状态还在变动。我们总不能每次条件不满足时都来保游戏

区的状态吧。这是一个错误的想法。。J

那具体到游戏里我们应该在那里保存游戏区的状态呢?

首先 WM_KEYDOWN消息里肯定是不行的,因为此时我们还不能确定到

底方块是不是真的运动到低端或是遇到方块不能再移动了。

其次 WM_CREATE消息就更不用说了。WM_CREATE消息只在窗口创建的

时候由CreateWindow函数产生。在程序执行期间是不会产生此消息

的。至于WM_PAINT消息是在窗口创建成功后由UpdateWindow

数产生。但是在程序运行过程中我们可以利用IvalidateRect函数来

产生此消息。另外我们移动窗口,改变窗口的大小等也会产生

WM_PAINT消息。既然这样我们是否就可以在WM_PAINT消息中来

保存游戏区的状态了呢。其实我们感觉还真的可以。至于为什么可以。

等我说完下个消息你自然就清楚了。

最后WM_TIMER消息。这个消息由SetTimer定时来产生。即每隔一

定的时间。SetTimer函数就会发送一个这样的消息给窗口函数。看来

说不定它就是我们要找的地方了。因为我们以前在这个消息里做了一

个工作,那就是令方块自动下落。那好,假如我们SetTimer设定的

时间间隔为1秒。隔1秒,WM_TIMER来了,我们需要判断一下方

块的自动下落的条件是否满足。注意:这里的条件不满足可是和以前

的不一样啦。有啥不一样呢,不是都是用一个函数来判断的吗?是啊,

但是根据我们前面对条件的分析。条件大的方面分为两部分:1 范围,

2是否遇到方块。然而细分来说,这第1部分又可以分为两部分:①

左右范围出界②下范围出界 我们来看一下这三部分的条件都出现在

那种情况下:1 左右方位出界,这个肯定出现在按下左右键的时候啦。

即出现在WM_KEYDOWN消息里面。至于此时下范围是否出界这个

条件是否满足还真是个大问题,此处我觉得在条件判断是应该下范围

的条件判断放在最前面,为什么这么说呢。这里的设计是为了满足在

达到最低端时按下左右键时,此时应该不予响应。那为什么这样就不

响应了呢?因为这样在进行条件判断时,它首先判断第一个条件,若

满足,则在我们这样形式(… ||…||…||…||…)的条件,它就不会再往

下判断了,因为只要有一个为1,整体的结果就为1.故我建议将下范

围的条件判断放在首位。好我们再看下范围的条件不满足出现在什么

条件下,毋庸置疑的就是落到底端或是遇到方块不能自动下落时。然

而产生这种条件的环境也正是WM_TIMER里的条件不能满足的时

候,哈哈,我们终于找到它了。我们可以在WM_TIMER中条件不满

足的时候来保存我们的状态。好,我们现在再返回上个讨论的消息WM_PAINT,为什么我说在WM_PAINT消息里也可以呢。其实这

个也是基于InvalidateRect函数的。由于我们可以使用这个函数在任

何时候产生我们想要的消息,故我们就可以这样的设计,在WM_TIMER里的条件不满足时,我们就调用InvalidateRect函数产

WM_PAINT消息,这样我们不就可以在WM_PAINT消息里来保

存我们当前的游戏状态了吗?呵呵。。

7 显示问题

说了这么多了,一个主要的问题还没说,那就是在我们移动图形的时

候会发现,原来的图形还留在那里。这时候我们该怎么办呢。不用说,

区擦除它。。呵呵。擦了就干净了。如何做呢?这里有另种方法:

1 我们只需在用两个POINT型变量来保存当前图形和上一个图形的形状,方向,坐标。然后在每次移动的时候用背景色的画笔将上个图形再画一遍就好了,这样上次的图形就被覆盖了,由于我们新画的图形又和背景色一致,故我们看不到。然后再把当前的图形画上就OK了。

2 利用擦除背景法,即我们在每次移动一个图形后,将整个游戏区用背景色的画刷再刷一边,这样所有的图形都没了,然后重新画上游戏区,原有图形和当前图形。也OK了。

8 如何消去方块

当我们一行里的方块满时,我们该如何判断呢?我们又应该如何把它消去呢?这时就用上我们刚才的哪个状态数组了。我们利用查找法,区查找状态数组,若数组的某一行全部为1了。就说明这行满了。下面我们就该把它消去了,如何消去呢?我们可以设想一下,把这样消去就说明这行原来的图形不存在了。也就是说原来图形的状态也就应该离开了,这里应明白的是:方块虽然消去了,游戏去仍然在,这一行仍然在,游戏中我们需用上面一个行落下来来填充这一行。故我们同样需要上面一行的状态来覆盖原来的状态来对应于当前行的状态。由此这行就被消去了。至于游戏的得分和消去的行数,级别等,我们只需设置相应的变量(全局或静态)来表示即可:如我们设置行数为int count = 0;这样我们可以在判断一行满的条件满足时自动加1即可。

至于分数我们可以根据消去行数来计算,如一行加10分,级别吗,我们也可以通过分数来计算,即当超过多少分时升级。

至此,一个俄罗斯方块的思想已经基本完成了。

原创粉丝点击