俄罗斯方块单人版1、需求分析俄罗斯方块,或称积木游戏,它是利用一些形状各异却又是用正方形组成的方块,经过不同位置不同角度的变化之后,堆积在一起的一种智力游戏。
2、概要设计而从编程的角度讲,只需要提供各种方块的图形,提供几个键盘操作键以供方块的形状和位置的变化,提供几个功能函数以供游戏的正常进行。
各种方块图形:利用数组定形,然后利用随机函数随机地不按顺序地按游戏的需要而出现。
功能函数将在变量函数里面介绍。
3、详细设计添加位图:封面:IDB_BITMAP1背景:IDB_BITMAP2方块:IDB_BITMAP4添加菜单:开始:ID_MENU_START接着就是定义变量了,但是,由于这个游戏要添加的变量和函数太多了,要建一个新类。
是否应该先添加应该类呢?最好是这样。
因为新类将会涉及到变量。
添加普通类Crussia,见下图。
图4-1-1添加变量函数:由于两个类一共有很多变量函数,列举如下:View.h :Public://俄罗斯类CRussia russia;//开始标志bool start;//封面CBitmap fenmian;//暂停BOOL m_bPause;//开始菜单afx_msg void OnMenuStart();//计时器afx_msg void OnTimer(UINT nIDEvent);//键盘操作afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);// Russia.h:Public://游戏数组int Russia[100][100];// 当前图形int Now[4][4];//上一图形int Will[4][4];//变换后的图形int After[4][4];//当前图形的左上角位置CPoint NowPosition;//当前可能出现的图形形状数,int Count;//游戏结束bool end;//级别int m_Level;//速度int m_Speed;//分数int m_Score;//行列数int m_RowCount,m_ColCount;//方块CBitmap fangkuai;//背景CBitmap jiemian;//显示分数等内容void DrawScore(CDC*pDC);//消行void LineDelete();//方块移动void Move(int direction);//方块变化,即方向键上键操作bool Change(int a[][4],CPoint p,int b[][100]);//是否与原来方块接触,或与边界接触bool Meet(int a[][4],int direction,CPoint p);//显示下一个方块void DrawWill();//显示界面void DrawJiemian(CDC*pDC);//开始void Start();然后,就可以一步一步地实现游戏了。
函数依然是一个一个添加,如果有还没定义的函数,添加空函数。
以保证程序的条理性和可运行性。
设置窗口大小:BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){if( !CFrameWnd::PreCreateWindow(cs) )return FALSE;// TODO: Modify the Window class or styles here by modifying// the CREATESTRUCT cscs.cx=500;cs.cy=590;return TRUE;}构造函数:CMy4_1View::CMy4_1View(){// TODO: add construction code herefenmian.LoadBitmap(IDB_BITMAP1);start=false;m_bPause=false;}CRussia::CRussia(){jiemian.LoadBitmap(IDB_BITMAP2);fangkuai.LoadBitmap(IDB_BITMAP4);}画图函数:void CMy4_1View::OnDraw(CDC* pDC){CMy4_1Doc* pDoc = GetDocument();ASSERT_VALID(pDoc);// TODO: add draw code for native data hereCDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can't create DC");//没有开始,显示封面if( !start){Dc.SelectObject(fenmian);pDC->BitBlt(0,0,500,550,&Dc,0,0,SRCCOPY);}//显示背景elserussia.DrawJiemian(pDC);}开始时是设start为假,它就会在OnDraw()函数中画封面,而当开始游戏,start为真,那么,它干什么呢?画背景!其函数如下:界面函数:还是那个道理,当有一些客户区生效(被挡住或最小化)时,它必须重画,而如果游戏只是玩了一半,它必然在重画时必须把原先已经出现的方块、分数等也显示出来,怎么办?就必须在画封面的同时也画出它们。
当然,刚开始时它们是不会符合条件的。
void CRussia::DrawJiemian(CDC*pDC){CDC Dc;if(Dc.CreateCompatibleDC(pDC)==FALSE)AfxMessageBox("Can't create DC");//画背景Dc.SelectObject(jiemian);pDC->BitBlt(0,0,500,550,&Dc,0,0,SRCCOPY);//画分数,速度,难度DrawScore(pDC);//如果有方块,显示方块//游戏区for(int i=0;i<m_RowCount;i++)for(int j=0;j<m_ColCount;j++)if(Russia[i][j]==1){Dc.SelectObject(fangkuai);pDC->BitBlt(j*30,i*30,30,30,&Dc,0,0,SRCCOPY);}//预先图形方块for(int n=0;n<4;n++)for(int m=0;m<4;m++)if(Will[n][m]==1){Dc.SelectObject(fangkuai);pDC->BitBlt(365+m*30,240+n*30,30,30,&Dc,0,0,SRCCOPY);}}信息函数:其中还涉及另外一个函数DrawScore(pDC),它是画分数、速度、难度(本程序省略)的。
由于它的代码不是太少,另外用了一个函数,这样有利于理解。
void CRussia::DrawScore(CDC*pDC){int nOldDC=pDC->SaveDC();//设置字体CFont font;if(0==font.CreatePointFont(300,"Comic Sans MS")){AfxMessageBox("Can't Create Font");}pDC->SelectObject(&font);//设置字体颜色及其背景颜色CString str;pDC->SetTextColor(RGB(39,244,10));pDC->SetBkColor(RGB(255,255,0));//输出数字str.Format("%d",m_Level);if(m_Level>=0)pDC->TextOut(440,120,str);str.Format("%d",m_Speed);if(m_Speed>=0)pDC->TextOut(440,64,str);str.Format("%d",m_Score);if(m_Score>=0)pDC->TextOut(440,2,str);pDC->RestoreDC(nOldDC);}至此,可以看的都画完了。
程序一般都是会先处理图形界面,因为这样在编核心内容时能够让人有一个检查的机会。
菜单开始函数:现在,游戏总该开始了吧。
添加菜单开始函数:ID_MENU_START其函数如下:void CMy4_1View::OnMenuStart(){// TODO: Add your command handler code herestart=true;russia.Start();SetTimer(1,50*(11-russia.m_Speed ),NULL);}先把start赋值为true,再调用russia.Start()函数,让它对俄罗斯方块游戏的相应变量赋值,为了使游戏能够调整速度,设置一个可变的计数器。
那么,russia.Start()函数做了什么呢?开始函数:void CRussia::Start(){end=false;//运行结束标志m_Score=0; //初始分数m_Speed=0; //初始速度m_Level=1; //初始难度m_RowCount=18; //行数m_ColCount=12; //列数Count=7; //方块种类//清空背景数组for(int i=0;i<m_RowCount;i++)for(int j=0;j<m_ColCount;j++){Russia[i][j]=0;}//清空方块数组Now[ ][ ] Will[ ][ ]for(i=0;i<4;i++)for(int j=0;j<4;j++){Now[i][j]=0;Will[i][j]=0;}//先画Will[][]DrawWill();//再画Now[][]&Will[][]DrawWill();}预备方块:DrawWill()的作用是,把预备方块给当前方块,再生成一个预备方块。
由于开始时预备方块自己都没有,它根本就不能拿一个方块给当前数组,它只能自己生成一个,这也是什么连续调用两次的原因。
void CRussia::DrawWill(){int i,j;int k=4,l=4;//把将要出现的方块给当前数组,并把将要出现数组赋值为零for(i=0;i<4;i++)for(j=0;j<4;j++){Now[i][j]=Will[i][j];Will[i][j]=0;}//初始化随即数种子//其中是什么意思?不知道的话,不如按一下F1。