[原创]MFC实现的俄罗斯方块

[原创]MFC实现的俄罗斯方块_第1张图片

MFC实现的俄罗斯方块,上学期期末复习着无聊的时候做出来的,每天做一点,最后居然顺利做出来.做了之后才发现,要做成这个小游戏,值得考虑的地方还是很多的.想了想就有以下的一些细节,总结起来有以下几点:

1.   关于方块结构的确定,最初考虑的是用4*4的数组来表示一个方块,但这就意味着每个方块会造成远大于自身的存储空间的浪费,而且按照这种思路,方块每切换一次形状,就要对一个4*4的数组数据进行重写,时间和空间效率都不高.在考虑换种表示方法的时候,突然观察到,其实俄罗斯方块里的每个方块都是由4个格子组成的,只要定义一个大小为4的结点数组就能很好的保存方块的位置了.于是Node结构就这样成了.

typedef struct node

{

                  int x;

                  int y;

}Node;

 

2.   有了这个结构之后,就该考虑如何表示方块了,因为使用的是MFC,而上学期又系统的学了C++,于是考虑了用面向对象的方法来实现这几个方块,从面向对象的角度来看,这几个方块确实具有惊人的相似度,首先,它们都是由四个格子组成,其次,都能由键盘可控制移动,然后,都能通过某个按键(本程序定义用空格)来切换形态,最后,也是理所当然的能够被显示出来.所以,我为这些方块定义了一个名叫CBase 的抽象类作为它们的基类,而由于这些方块的左右移动和着陆方法都是相同的,所以在基类中就实现了这几种方法,充分体现了面向对象的代码重用机制,最重要的是也省去了写重复代码的麻烦.

         class CBase

{

public:

     Node node[4];                                                                            //用于存放结点

     CBitmap bm;                                                                                       //格子的图片

     int State;                                                                                     //用于标识当前的形态

     bool bmLoaded;                                                                                  //图片是否成功导入

public:

     virtual void Set(int x,int y)=0;                              //初始化方块出现的位置

     virtual void Draw(CDC *pDC,CWnd *pWnd)=0;               //显示方块

     virtual void Change(const CBackGround bk)=0;      //切换形态

     bool Landed(const CBackGround bk);                                  //是否已经着陆

     void Down();                                                                               //落下     

     void RMove(const CBackGround bk);                                  //右移

     void LMove(const CBackGround bk);                                   //左移

     void Show(CDC *pDC);                                                           

//ShowDraw不同,专门用于显示下一个方块

     void RefreshShowRect(CWnd* pWnd);                               //刷新下一个方块

};

3.  有了这个基类后,方块类只用重写继承来的虚函数就可以,让自己成为特定的方块了,在重写这些虚函数时,最重要的当然是显示的问题了,在做这个程序之前,看见一篇文章,介绍如何使用无闪烁重绘,所以就把这种方法用进来了,其结果就是为了实现无闪烁,计算了大量的方块移动后需要重绘的区域,实在是痛苦…..好在最后还是把这个功能实现了.在代码里也可以看到Draw方法里面很多行都用在计算坐标然后调用InvalidateRect()上了.

4.  俄罗斯方块总共有7种方块,每个方块就对应一个继承于CBase的类.在这些类中另一个重要的实现细节就是如何判断方块成功着陆了.在俄罗斯方块中,成功着陆分为两种情况,第一就是落到最下层的地面,第二就是落在了其他方块上面.显然这两种着陆方式是由本质不同的.如果要成功实现这两种方式,至此就必须考虑怎样把已着陆的方块和玩家正控制的方块联系起来.从这个问题出发,构造了CBackGround,已着陆的类就好像背景一般的存在.那么,第一种着陆方式就可以直接判断当前方块的格子y坐标是否有和地面相同的,而第二种着陆,就判断当前方块格子y坐标是否有和CBackGround中格子相同的.那么着陆的问题就解决了.以下便是CBackGround

         class CBackGround

{

public:

  Node node[1200];                      //格子

     int top;                                          //把所有格子看成栈,top就是栈顶指针

     int nCleared;                                //是否符合消去的条件

public:

     CBackGround();                                    //构造函数

     void Draw(CDC *pDC,CWnd *pWnd); //显示所有的格子

     void GetNode(CBase *pBase);                  //得到当前方块的节点并贮存

     void Clear(CWnd *pWnd);                          //消去

     bool GameOver();                                //游戏结束

     int GetClearedNum();                         //用于计分

};

5.  构造这个类,还考虑其他的一些问题.比如,1.既然是用于表示已着陆的方块的类,那么关于消去的方法也理所应当在这个类里面实现,2.当前方块成功着陆后,就由当前方块变成了CBackGround的组成,GetNode()负责完成这个转变3.CBackGround中的某个节点的y坐标到某指定值时,就应该意味着游戏结束了.4.关于计分,首先在这个类中记录消去次数然后把这个次数传给一个CCounter计数器来统计和显示当前分值,个人设定的公式就是10*消去次数.

 

6.  这些自定义类完成后,程序也到了最后阶段了,那就是在MFC中使用的问题.首先,CMainFrame类中添加WM_GETMINMAXINFO消息,在消息响应函数中,把窗口的大小固定成了300*400;接着,CView类添加一系列将要使用的对象,其中有CBase类指针m_pBase,通过这个指针,就可以new出不同的方块了.

7.   说到方块的产生,就不得不提另一个问题了.俄罗斯方块中方块的产生都是随机的,每次运行游戏产生的方块都有可能不同.这是一种真的随机,Random()函数产生的却都是伪随机数,每次运行产生的结果是固定的,不符合要求.于是,考虑了用读取系统时间值并对7取模的方式来产生编号为0—6的方块,这样就模拟出了需求的随机效果.

8.   对于俄罗斯方块这个游戏的描述应该是,打开游戏后,有各种下落的方块,并能显示下一个出现的方块,用户可以控制当前方块直到它着陆,控制包括左右移动快速下移以及切换形态,当方块成功着陆后,控制下一个方块,如此循环.当一行充满格子时,该行被削去,增加计分值.

当方块累积到一定高度时游戏结束.能清晰描述后,该游戏的需求分析就完了,对于CView部分的代码,就是这些功能的具体实现.

 

9.  最后要说一下算法的问题,在写消去算法的时候,本来为了简化,我把多行的消去考虑为一行消去的递归形式,本来觉得这种考虑是正确的,起初也没有出现问题,但在某一次玩的时候,居然出现了消不动的情况,经过几次测试才发现,最早的算法是判断与当前方块着陆点有关的行数是否满足消去条件,然后逐行递归消去.但是俄罗斯方块也可以隔行消去,比如35行满足消去条件而4行不满足,由于考虑不足,出问题是自然的了.在改进之后,我采用了记录与当前方块着陆点相关的4行并判断它们是否满足消去条件.

 

 

你可能感兴趣的:([原创]MFC实现的俄罗斯方块)