流倏MFC俄罗斯方块

    最近对小游戏很有热情,做过24点游戏后觉得不是很完善,改了又改,最终还是那个样子,于是想做个新鲜的,于是开始把目光盯上了俄罗斯方块。好家伙,这个经典。小时候很喜欢玩的小游戏。哈,就是它了。。。

    于是就这样开始了我俄罗斯方块之路。

    首先还是算法,俄罗斯方块主要是界面刷新,开始想到把所有的方块形态(7个)用图片做出来,在定时器中移动图片的y坐标。图片是容易贴,y坐标也容易移动。可是方块的背景色在界面背景上显得很突兀,即使方块图片在PS中处理成透明色的,背景色也不是透明的。还有就是图片是矩形的,而在方块与方块接触的地方是不规则的,这样在方块与方块接触判断的地方出现了难题。开始想利用这种方法解决:选取要透明的RGB色作为透明色,用异或方式与原图比较,相同的保留,剩下的就是方块。这样方块距没有多余的部分了。但接触问题还是很难解决,还有就是消行的时候图片要丢掉一部分。这样下来,难度越来越大。

    意识到这种方法越来越不可行后,开始换一种思路,参考了一下网络,觉得用数组比较靠谱。先制作一张小方块单元的图片,利用一个4×4的二维数Russia[][]组来保存方块信息,为1的表示要画方块。再用m_ColCount×m_RowCount表示格子界面。用一个变量表示方块当前的(X,Y)坐标,用m_ColCount×m_RowCount的for循环对每个方块数组判断,为1的就贴上方块,这样也同样便实现了方块贴图的问题。而对于方块的接触问题,由于方块是由数组构成的,可以逐行逐列判断,即使是不规则的,也可以对方块小单元进行判断。而对于变形,也就转换成数组的变换。

    核心算法如下:

    建立一个CRussia类,在主类中声明一个Crussia类对象作为成员变量,各个功能的实现利用Crussia类对象调用Crussia类成员函数。

    Crussia类成员变量及函数:

    int Russia[20][10];//游戏数组

    int Now[4][4];// 当前图形

    int Will[4][4];//下一图形

    int After[4][4];//变换后的图形

    CPoint NowPosition;//当前图形的左上角位置

    int Count;//当前可能出现的图形形状数

    bool end;//游戏结束

    int m_Level;//级别

    int m_Score;//分数

    int m_TotalCount;//消去的行数

    int m_RowCount,m_ColCount;//行列数

    CBitmap cBlock;//方块

    CBitmap cBkgound;//背景

    void DrawScore(CDC*pDC);//显示分数等内容,在DrawJiemian()中调用

    void LineDelete();//消行

    void Move(int direction);//方块移动

    bool Change(int a[][4],CPoint p,int b[20][10]);//方块变化

    bool Meet(int a[][4],int direction,CPoint p);//是否与原来方块接触,或与边界接触

    void DrawNext();//显示下一个方块

    void DrawJiemian(CDC*pDC);//显示界面

    void Start();//开始

    void Start()函数对各个成员初始化,如Count=7,end=false,m_Level=0,m_Score=0,t m_TotalCount=0,m_RowCount=0,m_ColCount=0等;

    关键是一下几个函数:

    void LineDelete();//消行

    void Move(int direction);//方块移动

    bool Change(int a[][4],CPoint p,int b[20][10]);//方块变化

    bool Meet(int a[][4],int direction,CPoint p);//是否与原来方块接触,或与边界接触

    void DrawNext();//显示下一个方块

    void DrawJiemian(CDC*pDC);//显示界面

    l         void DrawJiemian(CDC*pDC)函数负责界面更新,是要频繁调用的函数,在方块每下落或变形的时候都要调用以显示界面更新。该函数负责一下内容:

    1.       画游戏背景,即把背景图片贴到设备描述表上;

    2.       调用void DrawScore(CDC*pDC);函数显示级别、行数、分数统计信息;

    3.       在m_ColCount×m_RowCount格子上画方块;

    4.       在下一个方块视图中画出下一个方块;

    l         void DrawNext();函数负责显示下一个方块,该函数并未画方块,只是把并当前的数组Will[][]赋值给Now[][],并重新给Will[][]赋值,产生下一个方块数组。

    l         void Move(int direction);函数负责方块移动,函数功能考调用bool Change(int a[][4],CPoint p,int b[20][10])、 bool Meet(int a[][4],int direction,CPoint p)、void LineDelete();来实现。bool Change(int a[][4],CPoint p,int b[20][10])函数负责方块变形,bool Meet(int a[][4],int direction,CPoint p)函数根据参数direction的不同,分别实现方块左移、右移、下移、下落的功能,该函数要调用bool Meet(int a[][4],int direction,CPoint p)函数判断方块是否接触或者出界。

    功能设计完成,开始着手。

    先用PS设计背景界面,随便在网上找了一张图弄了一下,再设计方块小单元20*20像素大小的,设计了七种颜色,在游戏时随机出现。

    在程序中导入图片,添加好主类成员函数和变量后,再添加一个Crussia类,同样添加成员函数和变量,然后一个一个实现函数功能,对于暂时没有写好的函数,声明后可以为空,但一定不要忘了实现,首先要保证程序的可运行性。

    然后就是艰苦、苦涩的代码编写过程,完全不是件轻松的事,编写、调试、运行、查资料,一把辛酸。

    这样写了好些天,最终程序大抵可以运行,欣喜之情油然而生。经过修改、测试,程序最终告成,运行界面如下:

    LiuShuTetris

     

    编写程序过程中有两点很纠结:

    1.              到底是用对话框编写还是用单文档编写,刚开始的时候我想到的是用对话框编写,因为游戏不占用很大的界面,而且有许多控件可以使用。但是在编写到方块控制的时候遇到了问题,我并不了解对话框和单文档对按键消息处理的不同,用来WM_KEYDOWN消息,结果运行起来,任我如何按键,方块没有任何反应,一个劲的下掉,那家伙,急的我。仔细把代码看了又看,死也找不出问题。于是后来改用单文档了,喝,没一点问题。我就纳闷了,百度了一下,原来对话框的按键消息被系统自动截获,对话框并不响应按键消息,只有重载BOOL PreTranslateMessage(MSG* pMsg)函数才能响应。呵,好家伙,害我重做了好多事。

    2.              界面刷新的问题。原本程序运行后各个功能都能实现,就是有一点,每刷新一次界面都要闪烁一下,看着很不舒服。找了各种方法,还是没解决,看网上说要双缓冲贴图,照着弄了,结果可好,闪是不闪了,可界面却不刷新了,密密麻麻,上面全是方块运动的痕迹。那个好看啊。折腾了好久,原来是双缓冲没用熟。双缓冲是先在内存中构建一与当前设备描述表兼容的DC,把要贴的图先画在该内存DC上,在把该内存DC的内容一次性贴到当前设备描述表,这样在界面重绘的时候界面直接贴上更新好的内容,看起来自然不会闪烁了。

     

    有兴趣的朋友可以下载试玩一下:

    CSDN:http://download.csdn.net/detail/sharlon123/4174950



    本站所有文章如无特别注明均为原创。
    转载请注明:流倏 » 流倏MFC俄罗斯方块

    点赞 | 0

已经有8 人抢在你前面了~

  • dolpstar 3年前 (2015-10-12)

    好厉害 博主哪里人 能否交个朋友 喝杯白酒

  • AnnaMJ 2年前 (2016-12-18)

    Hello! My name is AnnaMarkova, our company need to advertise on your website. What is your prices? Thank you. Best regards, Mary.

    • 流倏
      流倏 2年前 (2016-12-27)

      What’s your company name? And what advertisement you want to show on my site?

    • Minerva 1年前 (2017-01-06)

      A few years ago I’d have to pay someone for this infmoration.

  • Haroldevola 1年前 (2017-01-05)

    truly excellent factors

  • AngelaHyday 1年前 (2017-01-13)

    You always do the right thing. God Bless you.
    Thank you

  • Julietew 1年前 (2017-01-14)

    Good post! I read your blog often and you always post excellent content. I posted this article on Facebook and my followers like it. Thanks for writing this!

  • LuisaTat 1年前 (2017-01-15)

    whoa1h this blog is great i love reading your posts. Keep up the great work! You know, a lot of people are looking around for this information, you can aid them greatly.