《軟件建模與實踐》課件-10-俄羅斯方塊游戲_第1頁
《軟件建模與實踐》課件-10-俄羅斯方塊游戲_第2頁
《軟件建模與實踐》課件-10-俄羅斯方塊游戲_第3頁
《軟件建模與實踐》課件-10-俄羅斯方塊游戲_第4頁
《軟件建模與實踐》課件-10-俄羅斯方塊游戲_第5頁
已閱讀5頁,還剩46頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

俄羅斯方塊游戲軟件分析與設計過程文檔視圖結構軟件的架構主要內容

理解游戲開發中的邏輯抽象掌握文檔視圖結構軟件的設計課程目的重難點文檔視圖結構10.1需求分析

俄羅斯方塊(Tetris)游戲是由俄羅斯人阿列克謝·帕基特諾夫發明的。Tetris游戲開始后,由4個小方塊組成的不同形狀的磚塊隨機出現,之后從屏幕上方中央落下,玩家通過調整磚塊的位置和方向,使它們在屏幕底部拼出完整的一條或幾條,這些完整的橫條會被消除,玩家得到分數獎勵。沒有被消除掉的方塊不斷堆積起來,一旦堆到屏幕頂端,玩家便告輸,游戲結束。10.1需求分析

通過分析,Tetris游戲在一個m×n的矩形框內進行。游戲開始時,矩形框的頂部會隨機出現一個由四個小方塊構成的磚塊(七種形狀),每過一個很短的時間(我們稱這個時間為一個tick),它就會下落一格,直到它碰到矩形框的底部,然后再經過一個tick,它就會固定在矩形框的底部,成為固定塊。接著再過一個tick頂部又會出現下一個隨機形狀,同樣每隔一個tick都會下落,直到接觸到底部或者接觸到下面的固定塊時,再過一個tick它也會成為固定塊,再過一個tick之后會進行檢查,發現有充滿方塊的行則會消除它,同時頂部出現下一個隨機形狀。直到頂部出現的隨機形狀在剛出現時就與固定塊重疊,表示游戲結束。10.1需求分析由上可知,系統需要完成的功能如下:(1)方塊生成:當游戲運行開始或方塊成為固定塊后,應能在游戲面板頂部隨機生成一個新方塊,這樣便于玩家提前進行控制處理。(2)方塊控制:游戲玩家可以對出現的方塊進行移動處理,分別實現左移、右移、旋轉、快速下移、自由下落和行滿自動消除功能的效果。10.1需求分析(3)更新顯示:當在游戲中移動方塊時,需要先消除先前的游戲方塊,然后在新坐標位置重新繪制該方塊。(4)分數與速度更新:設定玩家得分獎勵的規則,例如,可以設置消除完整的一行得10分,兩行得30分。當分數達到一定數量后,需要給游戲者進行等級上的升級,并升級難度,例如,當玩家級別升高后,方塊的下落速度將加快。(5)系統幫助:玩家進入游戲系統后,通過幫助了解游戲的操作方式。10.2設計過程10.2.1

功能設計根據需求分析,俄羅斯方塊游戲的功能結構如圖10-1所示。圖10-1

俄羅斯方塊游戲軟件功能結構圖10.2.1

功能設計1.方塊生成新游戲的方塊使用隨機函數rand()可以產生0~6之間的游戲方塊編號。2.方塊控制方塊的移動控制是整個游戲的重點和難點,具體為:(1)左移處理過程。①判斷是否能夠左移,判斷條件有兩個:左移一位后方塊不能超越游戲底板的左邊線,否則將越界;并且在游戲方塊有值(值為1)的位置,游戲底板是不能被占用的(占用時值為1)。10.2.1

功能設計②清除左移前的游戲方塊。③在左移一位的位置處,重新顯示該游戲方塊。(2)右移處理過程。①判斷是否能夠右移,判斷條件有兩個:右移一位后方塊不能超越游戲底板的右邊線,否則將越界;游戲方塊有值的位置,游戲底板不能被占用。②清除右移前的游戲方塊。③在右移一位的位置處,重新顯示該游戲方塊。10.2.1

功能設計(3)下移處理過程。①判斷是否能夠下移,判斷條件有兩個:下移一位后方塊不能超越游戲底板的底邊線,否則將越界;游戲方塊有值的位置,游戲底板不能被占用。滿足上述兩個條件后,可以被下移處理。②清除下移前的游戲方塊。③在下移一位的位置處,重新顯示該游戲方塊。10.2.1

功能設計(4)旋轉處理過程。①判斷是否能夠旋轉,判斷條件有兩個:旋轉后方塊不能超越游戲底板的底邊線、左邊線和右邊線,否則將越界;游戲方塊有值的位置,游戲底板不能被占用。②清除旋轉前的游戲方塊;③

在旋轉后的位置處,重新顯示該游戲方塊。10.2.1

功能設計3.更新顯示當游戲中的方塊在進行移動處理時,要清除先前的游戲方塊,用新坐標重繪該游戲方塊。當消除滿行后,要重繪游戲底板的當前狀態。4.速度分數更新當行滿后,積分變量score會增加一個固定的值,然后將等級變量level和速度變量speed相關聯,實現等級越高速度越快的效果。需要一個檢查一行是否填滿的函數。10.2.2類的設計俄羅斯方塊游戲的業務邏輯主要需要對兩個類進行類設計,一是游戲面板矩形框類;二是磚塊類。1.俄羅斯方塊游戲的矩形框類——CBin首先,定義一個CBin類描述俄羅斯方塊游戲的矩形框。對矩形框進行分析,它應該有三個私有的數據成員:image、width和height。CBin類將俄羅斯方塊游戲的矩形框描述成為一個二維數組image,變量width和height存儲了image的維數,如圖10-2所示。有磚塊的地方的值為磚塊的顏色值(例如1為紅色,4為藍色),沒有磚塊的地方應為0值。10.2.2類的設計圖10-2

俄羅斯方塊游戲的矩形框接下來為CBin類添加5個成員函數,函數說明如表10-1所示。表10-1CBin類的成員函數說明函數名稱函數說明CBin(unsignedintw,unsignedinth)構造函數,用來初始化數據成員width和height,并為image分配空間并初始化~CBin()析構函數,刪除在構造函數中為image分配的空間voidgetImage(unsignedint**destImage)將image的數據拷貝到destImage,可以假設destImage指向的空間足夠容納image的數據voidsetImage(unsignedint**srcImage)把srcImage中的數據拷貝到image,你可以假設srcImage是一個合法的指針unsignedintremoveFullLines()檢查image,如果任何一行完全填滿,則刪除這一行,并讓上面行的數據下移一行,返回刪除的總行數10.2.2類的設計2.俄羅斯方塊游戲的磚塊類接下來完成游戲的磚塊類,常用磚塊如圖10-3所示。圖10-3

俄羅斯方塊游戲的矩形框10.2.2類的設計每個磚塊的基本形狀都是由4個子塊組成,在此基礎上對這4個子塊基于x、y方向上的相對位置進行編碼,分別得到以下兩組二維數組。

其中,brickX存放了7種磚塊中4個子塊的x坐標,brickY存放了7種磚塊中4個子塊的y坐標。staticintbrickX[7][4]={{0,1,2,3},{0,1,1,2},{2,1,1,0},{1,1,2,2},{0,0,1,2},{2,2,1,0},{0,1,1,2}};staticintbrickY[7][4]={{0,0,0,0},{0,0,1,1},{0,0,1,1},{0,1,0,1},{0,1,1,1},{0,1,1,1},{0,0,1,0}};CBrick類的成員函數說明如表10-2所示。表10-2CBrick類的成員函數說明函數名稱函數說明CBrick();構造函數unsignedintgetColour()獲得填充的顏色voidsetColour(unsignedintnewColour)設置填充顏色boolmove(intoffsetX,intoffsetY,unsignedint**binImage)實現磚塊的移動,可向左、向右、向下移動一格boolrotate(unsignedint**binImage);實現磚塊的旋轉voidoperator>>(unsignedint**binImage);重載運算符>>,通過設置映射到游戲矩形的2維數組binImage設置磚塊的顏色,這里假設binImage是一個合法的大小合適的2維數組10.3具體實現采用C++?面向對象程序設計語言,對俄羅斯方塊游戲的業務邏輯類進行實現。1.矩形框類的實現CBin類的類定義和函數實現分別在文件bin.h和bin.cpp中完成,函數代碼如下://文件bin.h#ifndefBIN_H#defineBIN_HclassCBin{private:unsignedint**image;unsignedintwidth;unsignedintheight;public:CBin(unsignedintw,unsignedinth);~CBin();unsignedintgetWidth(){returnwidth;};unsignedintgetHeight(){returnheight;};voidgetImage(unsignedint**destImage);voidsetImage(unsignedint**srcImage);unsignedintremoveFullLines();};#endif//實現文件bin.cpp#include"bin.h"CBin::CBin(unsignedintw,unsignedinth){width=w;height=h;image=newunsignedint*[height];for(unsignedinti=0;i<height;i++){image[i]=newunsignedint[width];for(unsignedintj=0;j<width;j++)image[i][j]=0;}}CBin::~CBin(){for(unsignedinti=0;i<height;i++){deleteimage[i];}delete[]image;}voidCBin::getImage(unsignedint**destImage){for(unsignedinti=0;i<height;i++)for(unsignedintj=0;j<width;j++)destImage[i][j]=image[i][j];}voidCBin::setImage(unsignedint**srcImage){for(unsignedinti=0;i<height;i++)for(unsignedintj=0;j<width;j++)image[i][j]=srcImage[i][j];}unsignedintCBin::removeFullLines(){unsignedintflag,EmptyLine=0;unsignedinti,j,m;for(i=0;i<height;i++){flag=0;for(j=0;j<width;j++){if(image[i][j]==0)flag=1;}

//當一行被完全填滿if(flag==0){for(j=0;j<width;j++){image[i][j]=0; //當前行清零,即刪除}

//上面的磚塊下落for(m=i;m>0;m--){for(j=0;j<width;j++){image[m][j]=image[m-1][j];}}for(j=0;j<width;j++){image[0][j]=0;}EmptyLine++; //記錄被刪除的行數i--; }}returnEmptyLine;}2.磚塊類的實現#ifndefBRICK_H#defineBRICK_H#include"bin.h"staticintbrickX[7][4]={{0,1,2,3},{0,1,1,2},{2,1,1,0},{1,1,2,2},{0,0,1,2},{2,2,1,0},{0,1,1,2}};staticintbrickY[7][4]={{0,0,0,0},{0,0,1,1},{0,0,1,1},{0,1,0,1},{0,1,1,1},{0,1,1,1},{0,0,1,0}};CBrick類的說明如下(文件brick.h):classCBrick{protected:unsignedintcolour;unsignedintx[4];unsignedinty[4];public:CBrick();unsignedintgetColour(){returncolour;};voidsetColour(unsignedintnewColour){colour=newColour;};boolmove(intoffsetX,intoffsetY,unsignedint**binImage); //移動boolrotate(unsignedint**binImage); //旋轉voidoperator>>(unsignedint**binImage); //輸出圖像};#endif#include"stdafx.h"#include"brick.h"#include<string.h>#include<malloc.h>CBrick::CBrick(){colour=(rand()%7)+1;for(inti=0;i<4;i++){x[i]=brickX[colour-1][i];y[i]=brickY[colour-1][i];}}CBrick的三個函數類外實現代碼如下(brick.cpp):boolCBrick::move(intoffsetX,intoffsetY,unsignedint**binImage){inti;intX[4],Y[4];for(i=0;i<4;i++) //針對每一個小方格的移動{X[i]=x[i]+offsetX;Y[i]=y[i]+offsetY;if(X[i]<0||X[i]>=10||Y[i]<0||Y[i]>=20)//判斷是否能夠移動成功returnfalse;if(binImage[Y[i]][X[i]]!=0)returnfalse;}for(i=0;i<4;i++){x[i]=X[i];y[i]=Y[i];}returntrue;}boolCBrick::rotate(unsignedint**binImage){inti;intxt[4],yt[4];for(i=0;i<4;i++){

//進行順時針90度坐標變換xt[i]=y[i]+x[1]-y[1];yt[i]=x[1]+y[1]-x[i];if(xt[i]<0||xt[i]>=10||yt[i]<0||yt[i]>=20)returnfalse;if(binImage[yt[i]][xt[i]]!=0)returnfalse;}for(i=0;i<4;i++){x[i]=xt[i];y[i]=yt[i];}returntrue;}voidCBrick::operator>>(unsignedint**binImage){for(inti=0;i<4;i++)binImage[y[i]][x[i]]=colour;}10.3具體實現3.可視化的設計在VisualStudio2010平臺下完成可視化的設計。(1)用MFC應用程序向導新建一個單文檔應用程序NewTetris。在新建對話框中進行設置,項目類型選擇Singledocument,語言選擇中文簡體,去掉UseUnicodelibraries的勾選,項目風格選擇MFCstandard,其他頁面采用默認值,如圖10-4所示。圖10-4

MFC應用程序向導新建對話框(2)將bin.h、bin.cpp、brick.h、brick.cpp文件加入NewTetris工程。并在NewTetrisView.h文件前部添加:#include"bin.h"#include"brick.h"(3)游戲界面的可視化主要在視圖類中實現。在視圖類的類定義中添加如下成員變量:CBin*bin; //定義游戲矩形框指針CBrick*activeBrick; //定義指向當前下落磚塊的指針intgameOver; //判斷游戲是否結束intbrickInFlight; //判斷磚塊是否處于下落狀態intbrickType; //磚塊類別unsignedintinitOrientation; //初始狀態intnotCollide; //沖突否

unsignedintnumLines; //消的行數unsignedint**outputImage;intdifficulty; //定義游戲難度(4)在視圖類的構造函數中添加初始化代碼:CNewTetrisView::CNewTetrisView(){bin=newCBin(10,20);activeBrick=NULL;gameOver=1;brickInFlight=1;brickType=0;initOrientation=0;notCollide=0;numLines=0;difficulty=500;outputImage=newunsignedint*[20];for(inti=0;i<20;i++){outputImage[i]=newunsignedint[10];}bin->getImage(outputImage); }(5)在析構函數中添加如下代碼:CNewTetrisView::~CNewTetrisView(){

deletebin;}(6)在視圖類定義(NewTetrisView.h)中添加公有的成員函數的聲明:voidCNewTetrisView::DrawImage(CBin*bin,unsignedint**image,CDC*pDC){unsignedintwidth,i,j;unsignedintheight;width=bin->getWidth();height=bin->getHeight();intnSize=20;CRectrc;COLORREFBrickColor[8]={0xFFFFFF,0xFF0000,0x00FF00,0x0000FF,0x00FFFF,0xFFFF00,0x800000,0x800080}; for(i=0;i<height;i++){for(j=0;j<width;j++){rc=CRect(j*nSize,i*nSize,(j+1)*nSize,(i+1)*nSize);

//繪制面板if(image[i][j]!=0){pDC->FillRect(rc,&CBrush(BrickColor[image[i][j]]));}}}}在視圖類的實現文件(NewTetrisView.cpp)中,添加DrawImage函數的實現代碼:voidDrawImage(CBin*bin,unsignedint**image,CDC*pDC);(7)為工程添加如下菜單:頂級菜單ID_Game_Start開始(&S)難度(&D)屬性選擇pop-up,子菜單為:ID_DIFF_EASY 容易ID_DIFF_MID 中等ID_DIFF_SUP 高級(8)為ID_Game_Start、ID_DIFF_EASY、ID_DIFF_MID、ID_DIFF_SUP在視圖類中添加消息響應函數。并加入如下代碼:voidCNewTetrisView::OnGameStart(){gameOver=0;brickInFlight=0;numLines=0;for(unsignedinti=0;i<20;i++){for(unsignedintj=0;j<10;j++)outputImage[i][j]=0;}bin->setImage(outputImage);SetTimer(0,difficulty,NULL);}voidCNewTetrisView::OnDiffEasy(){difficulty=500;OnGameStart();}voidCNewTetrisView::OnDiffMid(){difficulty=350;OnGameStart();}voidCNewTetrisView::OnDiffSup(){difficulty=150;OnGameStart();}(9)為視圖類添加WM_TIMER的消息響應函數,并添加如下代碼:voidCNewTetrisView::OnTimer(UINTnIDEvent){unsignedintbinWidth,binHeight;unsignedinti=0;unsignedintj=0;CDC*pDC=GetDC();binWidth=bin->getWidth();binHeight=bin->getHeight();//startthegameif(!brickInFlight&&!gameOver){activeBrick=newCBrick;bin->getImage(outputImage);notCollide=activeBrick->move(binWidth/2,0,outputImage);if(notCollide){brickInFlight=1;activeBrick->operator>>(outputImage);Invalidate(FALSE);}else{

//程序結束gameOver=1;deleteactiveBrick;brickInFlight=0;}}if(brickInFlight&&!gameOver){bin->getImage(outputImage);notCollide=activeBrick->move(0,1,outputImage); //下落if(notCollide){activeBrick->operator>>(outputImage);}else{brickInFlight=0;//bin->getImage(outputImage);activeBrick->operator>>(outputImage);bin->setImage(outputImage);Invalidate(FALSE);numLines=numLines+bin->removeFullLines();bin->getImage(outputImage);}Invalidate(FALSE);}if(gameOver){KillTimer(0);if(MessageBox("輸了吧,還玩么","提示",MB_YESNO)==IDYES)OnGameStart();else//exit(0);PostQuitMessage(0);

//這兩種方法都可以退出程序}CView::OnTimer(nIDEvent);}(10)在視圖類的OnDraw函數中添加如下代碼:voidCNewTetrisView::OnDraw(CDC*pDC)//去掉參數pDC兩邊的注釋符{CNewTerisDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);pDC->Rectangle(0,0,200,400);charbuf[100];sprintf(buf,"分數:%d",numLines*10);pDC->TextOut(220,20,buf);DrawImage(bin,outputImage,pDC);}(11)為視圖類添加WM_KEYDOWN的消息響應函數,并添加如下代碼:voidCNewTetrisView::OnKeyDown(UINTnChar,UINTnRepCnt,UINTnFlags){bin->getImage(outputImage);if(nChar==VK_RIGHT&&!gameOver)activeBrick->move(1,0,outputImage); //向右elseif(nChar==VK_LEFT&&!gameOver)activeBrick->move(-1,0,outputImage);elseif(nChar==VK_UP&&!gameOver)activeBrick->rotate(outputImage);elseif(nChar==VK_DOWN&&!gameOver)while(activeBrick->move(0,1,outputImage));

//一鍵下落activeBrick->operator>>(outputImage);//輸出圖形//updatethedisplayif(!gameOver)Invalidate(FALSE);CView::OnKeyDown(nChar,nRepCnt,nFlags);}(12)編譯、鏈接、運行。4.實現磚塊的三維化前面的程序的磚塊繪制出來是平面的,看起來不是很美觀,我們添加一些函數,使得磚塊看起來有三維的效果。在視圖類定義(NewTetrisView.h)中添加兩個公有的成員函數的聲明:COLORREFGetLightColor(COLORREFm_crBody);COLORREFGetDarkColor(COLORREFm_crBody);在NewTetrisView.cpp文件前部添加:#defineCOLOR_CHANGE60在視圖類的實現文件(NewTetrisView.cpp)中,添加這兩個函數的實現代碼:COLORREFCNewTetrisView::GetLightColor(COLORREFm_crBody){BYTEr=GetRValue(m_crBody);BYTEg=GetGValue(m_crBody);BYTEb=GetBValue(m_crBody);r=r+COLOR_CHANGE>255?255:r+COLOR_CHANGE;g=g+COLOR_CHANGE>255?255:g+COLOR_CHANGE;b=b+COLOR_CHANGE>255?255:b+COLOR_CHANGE;returnRGB(r,g,b);}COLORREFCNewTetrisView::GetDarkColor(COLORREFm_crBody){BYTEr=GetRValue(m_crBody);BYTEg=GetGValue(m_crBody);BYTEb=GetBValue(m_crBody);r=r-COLOR_CHANGE<0?0:r-COLOR_CHANGE;g=g-COLOR_CHANGE<0?0:g-COLOR_CHANGE;b=b-COLOR_CHANGE<0?0:b-COLOR_CHANGE;returnRGB(r,g,b);}修改視圖類的DrawImage函數,添加如下黑體代碼:voidCNewTetrisView::DrawImage(CBin*bin,unsignedint**image,CDC*pDC){//省略前面代碼//繪制面板if(image[i][j]!=0){pDC->FillRect(rc,&CBrush(BrickColor[image[i][j]]));pDC->Draw3dRect(rc,GetLightColor(BrickColor[image[i][j]]),GetDarkColor(BrickColor[image[i][j]]));}

//省略后面代碼}圖10-5

編譯、鏈接、運行結果編譯、鏈接、運行結果如圖10-5所示。5.使用雙緩沖技術解決屏幕閃爍運行程序,會發現程序有些閃爍,這是因為程序受WM_TIMER消息觸發,調用OnTimer函數,OnTimer函數中調用的Invalidate函數會觸發對OnDraw函數的調用,從而不停地重繪窗口的結果。在VC++?的文檔/視圖結構中,CView的OnDraw函數用于實現絕大部分圖形繪制的工作。如果用戶改變窗口尺寸,或者顯示隱藏的區域,OnDraw函數都將被調用來重繪窗口。并且,當程序文檔中的數據發生改變時,一般必須通過調用視圖的Invalidate(或InvalidateRect)成員函數來通知Windows所發生的改變,對Invalidate的調用也會觸發對OnDraw函數的調用。正因為OnDraw函數被頻繁調用,所以在其執行時,每次都刷新填充一次客戶視圖區域,便會使屏幕不穩定,產生閃爍現象。采用雙緩沖方式可以消除屏幕閃爍。普通繪圖方式與雙緩沖繪圖方式的區別在于:普通繪圖方式可以看作是在屏幕上直接繪制圖形,雙緩沖繪圖方式是先在內存中創建的“虛擬屏幕”上繪制,然后將繪制完成的圖形一次性“拷貝”到屏幕上。修改視圖類的OnDraw函數:voidCNewTetrisView::OnDraw(CDC*pDC){CNewTetrisDoc*pDoc=GetDocument();ASSERT_VALID(pDoc);intm_nWidth,m_nHeight; CDCm_memDC;CBitmapm_memBmp;//1.用于映射屏幕的內存設備環境//獲取游戲窗口的大小用于下面設置內存位圖的尺寸CRectwindowRect;GetClientRect(&windowRect);m_nWid

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論