- 很經典的遊戲.簡單又讓人着迷.
今天就用mfc來實現個自己的俄羅斯方塊.運行截圖如下:
看起來還行吧..
網上有很多版本的實現代碼.但是看了幾個都是用一個很大的數組記錄這些下落的物體的形狀.然後寫一個很大的switch case來實現變形.感覺真麻煩.今天提出一個容易的實現方法.下面切入正題
思路是這樣的:
一:隨機生成物體
二:控制
1.變形
圍繞一個方塊向右旋轉90度.以變形
2.左右下移動
1>物體左右移動的時候不要過界.
2>物體落定後.
(1).設定它落下的位置.
(2).看是否滿了一行.滿了一行消去
(3).看是否方塊壘到頂了.到了game over
三:重複以上步驟
約定:
下落的會變形的那個小東東,我們叫 物體Object (--!!.大家忍受下這個名字.我是想不出其他的名字了.)
左側那個 物體在裏面移動的區域叫 遊戲區域 Block
實現這個遊戲的思路跟玩這個遊戲一樣簡單...
1,隨機生成一個物體.
2,響應鍵盤的輸入,做左右下移動和變形
3,物體落到底部,判斷是否滿一行,物塊壘滿一行消除之.壘到頂部game over
但是實現起來貌似又不是那麼簡單了.
首先看起來隨機生成一個不同形狀的物體就是挑戰
怎麼在視圖上畫一個個的不同形狀的物體呢?
我們看下這個遊戲.每個物體都是由更小的方塊組成.這些基本的小方塊沒有什麼不同,
再看看這個二維的遊戲界面,左邊的遊戲區域,一個個的小方塊合在一起是否就是我們所熟悉的二維數組?
假如我們把這個遊戲區域映射到一個二維數組,當這個數組元素有物體佔據的時候就在上面塗顏色,沒有則塗背景色.不就實現了麼?.
好了可以定義遊戲的區域的數據結構了.這個遊戲中由於要畫不同的顏色,因此數據結構可以如下定義:
- struct tagBlock
- {
- bSet;
- COLORREF color;
- }block[18][10]; // 我們將這個遊戲區域格式化爲 18*10 (row*col);
那麼畫一個物體又該如何畫呢?
假如我們先用數組定義好物體的形狀,然後移動變化,那就太麻煩了.可以看到這些物體都是更小的方塊組成的.(我們用四個小方塊組成一個大的物體).用四個小方塊,通過相對位置的不同可以變化成各種各樣的不同形狀.
我們最終是要在那個二維數組中畫不同形狀的物體.那麼在畫的時候就要直到當前的物體應該畫到哪兒.假如我們對二維數組的每個元素再抽象出來一個數據結構.在這個數據結構中保存當前它在二維數組中的位置(行列值).那就容易多了.
- typedef struct tagPane
- {
- int row; // 在block[18][10]的行
- int col; // 列
- }Pane;
這是一個小方格的定義,那每個物體要四個小方格,於是
- struct tagObject
- {
- Pane object[4];
- COLORREF color; // 每個物體有自己的顏色
- int t; // 對應於最上面的一個方塊的行值row
- int b; // 對應於最下面一個方塊行值
- int l; // 對應於最左面一個方塊的列值col
- int r; // 對應於最右面一個方塊列值
- };
由於我們要在畫一個當前的下落的物體和一個下次將出現的物體.因此定義兩個物體的對象
- tagObject Object,NextObject;
每個物體都是有邊界的(把四個小方格全部盛下的最小矩形邊界),我們把這個物體的四個小方塊當前在block中的行列值,記錄下來作爲邊界,放置在 tblr中.下面很多地方是用到這幾個值的
我們規定每個小方塊的實際大小是 (24*24)像素
那這個遊戲區域實際上就是 height = 18*24 ,width = 10*24大小的矩形內(要注意數組的行列和矩形寬高的對應,col 對應的是width, row 對應的是height)
- // 定義方格大小和遊戲區域的矩形
- const int PANE_WIDTH = 24; // 每個方格大小時24 * 24 pixel
- const CRect BLOCK_RECT = CRect(29,31,271,463); // 遊戲區域矩形
現在的問題是,你怎麼知道具體應該在視圖的哪個地方畫這些小方塊呢?
太簡單了.我們可以由行列值(row,col)立即得到它在視圖中所對應的矩形區域
CRect(col*PANE_WIDTH,row*PANE_WIDTH,(col+1)*PANE_WIDTH,(row+1)*PANE_WIDTH);
假如我們 要畫一個 物體,物體的四個方塊的行列值都知道的.比如是在二維數組中
(<0,0> <0,1> <1,0> <1,1>) 那
<0,0>對應的視圖的座標矩形是(0,0,24,24)
<0,1> -----(24,0,48,24)
....
自己那麼對比幾下就明白了.
可以寫一個函數專門獲取小方塊對應的實際視圖中的矩形區域(實際上,我們的遊戲區域不是從視圖的0,0開始畫的,而是上和左都有空白,左邊空白LEFT_MARGIN個像素,上邊空白是TOP_MARGIN個像素,因此是以(LEFT_MARGIN,TOP_MARGIN)點處作爲遊戲區域的左上角 .方塊的長和寬相等,定義爲PANE_WIDTH = 24)
- // 根據座標取得客戶區矩形
- CRect CRBlock::GetPaneRect(int row, int col)
- {
- if (row < 0 || col < 0)
- {
- return CRect(0,0,0,0);
- }
- return CRect(col*PANE_WIDTH+LEFT_MARGIN,row*PANE_WIDTH+TOP_MARGIN,
- (col+1)*PANE_WIDTH+LEFT_MARGIN,(row+1)*PANE_WIDTH+TOP_MARGIN);
- }
- //爲方便.給出另一個重載的版本
- // 由Pane的座標取得對應的客戶區的矩形
- CRect CRBlock::GetPaneRect(Pane *p)
- {
- return GetPaneRect(p->row,p->col);
- }
現在再繪製一個物體還難麼???張飛吃豆芽.!
- #define RANDOM_COLOR RGB(rand()%256,rand()%256,rand()%256)
- // 繪製當前下落的物體
- void CRBlock::DrawFallingObject(CDC *pDC)
- {
- CBrush brush(Object.color);
- CBrush brBorder(RANDOM_COLOR);
- CBrush *pOld = pDC->SelectObject(&brush);
- for (int i = 0; i < 4; i++)
- {
- CRect rc = GetPaneRect(&(Object.object[i]));
- if (!rc.IsRectNull()) //這個組成物體的小方塊 還未出現在遊戲區域內
- {
- pDC->Rectangle(&rc);
- pDC->FrameRect(&rc,&brBorder); // 繪製邊界,看起來會漂亮點哦.
- }
- }
- pDC->SelectObject(pOld);
- }
咦.鬱悶了...吃豆芽的時候遇到點problem.....
需要繪製下一個將出現的物體.這個物體不是繪製在遊戲區域內的.而是在遊戲區域的右側.
沒關係.假如我們在遊戲區域和這下個物體繪製的區域之間隔一個 方塊的寬度.所有的問題都又解決了,原來的函數還照樣可以用...
...繼續吃豆芽
- const CRect RECT_NEXTOBJECT = CRect(294,30,438,174); // 在這個矩形局域畫下一個物體 4*6 *PANE_WIDTH 大小
- //294 = LEFT_MARGIN + 10 * PANE_WIDTH + 1*PANE_WIDTH;
- 現在這個4*6的區域的 左上角,即是第一個方格的列座標就是 10+1 = 11 了.至於行座標,由於這個區域是和原來的遊戲區域上對齊的,所以依然是0;
- // 繪製下一個將出現的物體
- void CRBlock::DrawNextObject(CDC *pDC)
- {
- int l = NextObject.l;
- int t = NextObject.t;
- int r = NextObject.r;
- int b = NextObject.b;
- // 把 NextObject 的行列映射到 要畫在的矩形中
- int offsetRow = (0+(6-(b-t+1))/2)-t; /// 這只是要把物體畫到這個區域的中心
- int offsetCol = (11+(6-(r-l+1))/2)-l; //
- // 這一段只是美化
- CBrush brBkgnd(COLOR_BKGND);
- CBrush *pOld = pDC->SelectObject(&brBkgnd);
- CPen pen;
- pen.CreatePen(PS_SOLID,1,RANDOM_COLOR);
- CPen *pOldPen = pDC->SelectObject(&pen);
- pDC->Rectangle(&RECT_NEXTOBJECT);
- pDC->SelectObject(pOldPen);
- pDC->SelectObject(pOld);
- CBrush brush(NextObject.color);
- CBrush brBorder(RANDOM_COLOR);
- pDC->SelectObject(&brush);
- // 畫下一個物體
- for (int i = 0; i < 4; i++)
- {
- int row = NextObject.object[i].row;
- int col = NextObject.object[i].col;
- CRect rc = GetPaneRect(row+offsetRow,col+offsetCol);
- if (!rc.IsRectNull())
- {
- pDC->Rectangle(&rc);
- pDC->FrameRect(&rc,&brBorder);
- }
- }
- }
好了.萬事具備了.下次講如何生成不同形狀的物體物體
編程羣C,C++,MFC,Java 58698324.正招人.歡迎加入