俄罗斯方块mfc实验报告

程序设计实践

设计报告

课题名称:俄罗斯方块(MFC版)         

学生姓名:                 

班    级: 

班内序号:27                            

学    号: 

日    期:20##.6.1                   

1.  实验概述

1.1 课题目标和主要内容。

本课题的主要内容是用MFC实现经典游戏俄罗斯方块的编写。目标是能够正常运行,并且无过于严重的问题。使用的平台为MFC(基于对话框)。

1.2

采用计分升级制来进行游戏。当一次消去一行时,得一分,一次两行得4分,一次3行,得9分,一次4行,得16分。每50分为一个等级,得分足够则升级并重新开始游戏。

2.  程序设计

2.1 系统总体框架

用一个4维数组DiamondStruct[7][4][4][4]来表示所有的方块,用一个POINT类型的DiamondPos来表示方块当前的位置,然后通过一个二维数组BlockPanel[][],来表示整个游戏界面,同时进行障碍的添加。游戏过程中,通过改变DiamondPos来进行方块的下降以及左右移动,通过DiamondStruct[7][4][4][4]中第二个参数的改变来进行方块的变换。

2.2系统详细设计

【1】模块划分图及描述

【2】类关系图及描述

CWinApp与CDialog为基类。其它为添加的类。

【3】程序流程图及描述

  

【4】存储结构,内存分配

主要存储结构为数组。同时分配内存的有,画笔,Diamond类的指针,Panel类的指针,Block类的指针,Mill类的指针,Manager类的指针。

2.3 关键算法分析

【1】

bool Diamond::FullLine()

{

    bool IsFull,Full=false;

    pManager->SeriesLine=0;

    for(int iy=0;iy<=pPanel->nVGridNum;iy++)

    {

        IsFull=true;

        for(int ix=0;ix<=pPanel->nHGridNum;ix++)

        {

            if(!pBlock->BlockPanel[ix][iy]) IsFull=false;

        }

        if(IsFull)

        {  

            Full=true;

            pManager->SeriesLine++;

            for(int jy=iy;jy>0;jy--)

            {   Sleep(10);

                for(int jx=0;jx<=pPanel->nHGridNum;jx++)

                {

                    pBlock->BlockPanel[jx][jy]=pBlock->BlockPanel[jx][jy-1];

                }

            }

        }

    }

    pManager->LineNumber+=pManager->SeriesLine;

    pManager->Result+=pManager->SeriesLine*pManager->SeriesLine;

    if(Full)

        return true;

    else return false;

}

该算法实现的功能为,判断是否已经满行,并且若是满行,进行消行,加分的操作。该算法的时间复杂度为O(n)= 【(nVGridNum)^2*nHGridNum.】/2

【2】

bool Diamond::overlap()

{

    bool bTuFa=false;

    POINT TexPos;

    for(int iy=3;iy>=0;iy--)

    {

        for(int ix=0;ix<4;ix++)

        {

            if(DiamondStruct[DiamondType][DiamondState][ix][iy])

            {  

                TexPos.x=ix+DiamondPos.x;

                TexPos.y=iy+DiamondPos.y;

                pPanel->PanelPosToPos(TexPos);

                TexPos.y+=pPanel->GridSize.cy;

                if(TexPos.xPanelRect.left ||  

                   TexPos.x>pPanel->PanelRect.right||

                   TexPos.y>pPanel->PanelRect.bottom)

                   bTuFa=true;

                if(pBlock->BlockPanel[DiamondPos.x+ix][DiamondPos.y+iy]) bTuFa=true;

            }

        }

    }

    if(bTuFa) return true;

    return 0;

}

该算法的功能为实现判断方块是否与边界或者已有障碍重叠,若是重叠,则返回值0,若没有重叠,返回值1。算法的时间复杂度为O(1)

【3】

void Block::AddBlock()

{

    for(int iy=0;iy<4;iy++)

        for(int ix=0;ix<4;ix++)

        {

            if(pDiamond->DiamondStruct[pDiamond->DiamondType][pDiamond->DiamondState][ix][iy])

                BlockPanel[pDiamond->DiamondPos.x+ix][pDiamond->DiamondPos.y+iy]=true;

        }

}

该算法的功能为添加障碍,即当方块已经下降到不能下降的时候,将方块转化为障碍。该算法的时间复杂度为O(1)。

【4】

void Mill::MadeDiamond()

{

    pDiamond->DiamondType=PreDiamondType;

    pDiamond->DiamondState=PreDiamondState;

    pDiamond->DiamondPos.x=5;

    pDiamond->DiamondPos.y=0;

    int nmax=rand()%25;

    if((nmax>=0)&(nmax<=3)){

                    PreDiamondType=DIAMONDCAKE;

    }

    else if((nmax>=4)&(nmax<=7)){

        PreDiamondType=DIAMONDHOOK;

    }

    else if((nmax>=8)&(nmax<=11)){

   

        PreDiamondType=DIAMONDSEVEN;

    }

    else if((nmax>=12)&(nmax<=15)){

        PreDiamondType=DIAMONDHEAVE;

    }

    else if(nmax==16){

        PreDiamondType=DIAMONDBAR;

    }

    else if((nmax>=17)&(nmax<=20))

    {

        PreDiamondType=DIAMONDTWO;

    }

    else if((nmax>=21)&(nmax<=24)){

        PreDiamondType=DIAMONDSPADE;

    }

}

该算法的功能为生成新的方块,同时根据值的取值范围不同,确定每一种方块出现的概率。该算法的时间复杂度为O(1)。

【5】

void Manager::InitGame(int level)

{

    srand( (unsigned)time( NULL ) ) ;

    GetClientRect(theApp.m_pMainWnd->m_hWnd,&ClientRect);

    Result=0;

    LineNumber=0;

    Level=level;

    pPanel=new Panel;

    pPanel->PanelRect.top   =int(ClientRect.bottom*0.1f);

    pPanel->PanelRect.bottom=int(ClientRect.bottom*0.9f);

    pPanel->PanelRect.left  =int(ClientRect.right *0.1f);

    pPanel->PanelRect.right =int(ClientRect.right *0.6f);

    pPanel->nHGridNum       =14;

    pPanel->nVGridNum       =25;

    pPanel->GridSize.cx     =(pPanel->PanelRect.right-pPanel->PanelRect.left)/pPanel->nHGridNum;

    pPanel->GridSize.cy     =(pPanel->PanelRect.bottom-pPanel->PanelRect.top)/pPanel->nVGridNum;

    pPanel->PanelColor      =RGB(200,200,200);

    pPanel->TextRect.SetRect(int(ClientRect.right *0.7f),int(ClientRect.bottom*0.5f),int(ClientRect.right *0.95f),int(ClientRect.bottom *0.9f));

    pMill=new Mill;

    pMill->MillRect.top     =int(ClientRect.bottom*0.1f);

    pMill->MillRect.bottom  =int(ClientRect.bottom*0.2f);

    pMill->MillRect.left    =int(ClientRect.right *0.7f);

    pMill->MillRect.right   =int(ClientRect.right *0.8f);

    pMill->GridSize.cx      =(pMill->MillRect.right-pMill->MillRect.left)/4;

    pMill->GridSize.cy      =(pMill->MillRect.bottom-pMill->MillRect.top)/4;

    pMill->MillColor        =RGB(200,200,250);

    pMill->PreColor         =RGB(255,0,0);

    pDiamond=new Diamond;

    pDiamond->DiamondColor=RGB(100,100,255);

    pMill->MadeDiamond();

    pBlock=new Block;

    pBlock->BlockColor=RGB(255,255,100);

    Timer1=50;

    Timer2=350-Level*40;

    FallTimer=30;

    SetTimer(theApp.m_pMainWnd->m_hWnd,1,Timer1,NULL);

    SetTimer(theApp.m_pMainWnd->m_hWnd,2,Timer2,NULL);

}

该算法的功能为初始化游戏的数据,数据有页面的分配数据,各个部分的颜色数据以及定时器的数据。在这个函数里面,可以通过改变值来进行改变开始游戏时,游戏的初始设定。

该算法的时间复杂度为O(1)。

【6】

bool Manager::WhetherLoss()

{

    for(int ix=0;ix<=pPanel->nHGridNum;ix++)

    {

        if(pBlock->BlockPanel[ix][0])

        {

            SetFree();

            Sleep(2000);

            InitGame(1);

        }

    }

    return false;

}

该算法的功能为判断是否已经输了,如果最上面一行出现方块的话, 则判断为输。算法复杂度为O(N)= nHGridNum。

【7】

void Manager::OnTimer(UINT &nIDEvent)

{

    if(nIDEvent==1)

    {

        if(KeyLeft)

        {

            pDiamond->MoveDiamondLeft();

            DrawScene();

        }

        if(KeyRight)

        {

            pDiamond->MoveDiamondRight();

            DrawScene();

        }

    }

    else if(nIDEvent==2)

    {

        if(!pDiamond->MoveDiamondDown())

        {

            pBlock->AddBlock();

            pDiamond->FullLine();

            pMill->MadeDiamond();

            WhetherLoss();

            if(Result>=Level*50) PassLevel();

        }

        DrawScene();

    }

}

该算法实现的功能为定时器所要实现的作用,定时器1用来控制方块左右移动时的界面的刷新,定时器2用来实现方块下降时界面的刷新。

时间复杂度为O(n)=1。

【8】

void Manager::OnKeyDown(UINT &nChar)

{

    switch (nChar)

    {

    case VK_LEFT:

        KeyLeft=true;

        break;

    case VK_DOWN:

        SetTimer(theApp.m_pMainWnd->m_hWnd,2,FallTimer,NULL);

        KeyDown=true;

        break;

    case VK_RIGHT:

        KeyRight=true;

        break;

    case VK_UP:

    case VK_SPACE:

        pDiamond->RollDiamond();

        DrawScene();

        break;

    }

}

该算法的功能为按下一个按键后,所实现的功能。

时间复杂度为O(1)。

【9】

void Manager::OnKeyUp(UINT &nChar)

{

    switch (nChar)

    {

    case VK_LEFT:

        KeyLeft=false;

        break;

    case VK_DOWN:

        SetTimer(theApp.m_pMainWnd->m_hWnd,2,Timer2,NULL);

        KeyDown=false;

        break;

    case VK_RIGHT:

        KeyRight=false;

        break;

    case VK_UP:

    case VK_SPACE:

        KeySpace=false;

        break;

    }

}

该算法实现的功能为,当松开一个按键时,所实现的功能。

时间复杂度为O(1)。

【10】

void CMyDlg::OnPause()

{

    KillTimer(1);

    KillTimer(2);

    MessageBox("已°?暂Y停ª¡ê\n要°a开a始º?请?点Ì?击¡Â确¨¡¤定¡§","暂Y停ª¡ê",MB_OK);

    SetTimer(1,pManager->Timer1,NULL);

    SetTimer(2,pManager->Timer2,NULL);

}

该算法所实现的功能为,当暂停游戏时,所发生的事件。

算法的时间复杂度为O(1)。

3. 程序运行结果分析

主要的数据输入为键盘的按键输入。输出的显示方式为对话框中方块的移动以及变换。控制左右移动时画面显示的定时器的时间为50ms,控制下降的定时器的时间为350-level*40。整个运行过程并没有内存泄露,较为令人满意。

4.总结

4.1课题的难点及关键点。

本课题的难点主要还是对MFC的不了解,怎样让方块显示在屏幕上,又是怎么样显示方块的移动,怎么样用位图作为对话框的背景等等。

不过,最后通过查找资料以及网上的介绍,还是将这些问题一一的解决了。

本课题的关键点还是在于总体思路的把握。因为对于一个游戏来说,内部的联系是非常复杂与错乱的。如果不能很好的把握住总体的思路,最终将导致自己思路的混乱。

4.2 本课题的评价

对于本次课题的评价,我感觉还是很不错的,本次课题,无论是从综合性还是新颖度,都比较令人满意。而对于自己的评价,并不是特别的满意,由于第一次编写综合性程序,所以,刚开始时,并没有调整好思路,就直接开始编写,结果导致浪费了很多的时间以及精力,后来经过补救,才完成了实验。

4.3  心得体会

对于本次实验,心得与体会还是比较多的。

1.难度非常大。此次实验,是自己所编写的第一个游戏,跟以往不同,游戏的综合性以及代码长度等等,都提升了此次编程的难度,编写之后才知道并不是想象中的那么容易。

2.提升了自己的信心。这一次俄罗斯方块程序的完成,无疑大大加强了我的信心。在编写程序之前,从来没有想到过自己能编写出俄罗斯方块这样的游戏,因为在自己的理念中,自己的水平仍然是在较为基础的一段代码的编写,而此次的实验,让自己重新定位了自己的编写程序的水平以及高度,大大加强了自己的信心。

3.非常有成就感。当运行成功游戏之后,心里的成就感是非常强烈的,对于这个程序,花费了不少的时间,最终的完成,算是给了自己一个完美的交代,看着运行成功的游戏,也是自己所编写的第一个游戏,心里的成就感非常强烈。

4.提升了自己的兴趣。通过此次的编写成功,大大提升了自己对于编程的兴趣。既然我可以编写出俄罗斯方块这样的游戏,我也可以编写出其它的游戏,打算在暑假进一步的提升自己在编程游戏方面的能力。

5.参考文献

书本---------------------------C++高级语言程序设计

程序代码----------------------《俄罗斯方块1.0》

相关推荐