花了一週左右的時間終於寫好了最終版本的俄羅斯方塊,前一個版本的速度不是很快,並且代碼量大,維護不方便,今天下午又花了一下午重構這些代碼,使用了統一方法,使得代碼量比原來少了許多,邏輯比之前也更清晰了,速度也快了些。音樂也加上去了,按鈕也變成真正的按鈕了。數據和顯示分離,因此不少與顯示無關的代碼基本上均可以重用,很容易用qt寫個linux版本的,有興趣的能夠去試試。這個是下載地址http://kuai.xunlei.com/d/LJWDATTHYVJQ。
之因此想到寫這個小遊戲,是在上週的圖像處理課上面,又老師講到的矩陣變換想到了小時候常常玩的俄羅斯方塊的實現,花了一節課研究,大概知道了是怎麼實現的了,主要仍是一個2維數組,因而就決定花幾天時間把它寫起來,卻不知寫的過程當中,發送這樣或那樣的錯誤,究其緣由仍是根基沒打好,開始寫的一個方塊類,信息不是太多,因而又重構,算是比較穩定的版本,而後就根據繼續後續的開發工做,最後忽然有點寫不下去了,由於發現程序的邏輯太過繁瑣,因而就上網搜了下,看了好多,原本是想看看他們是怎麼寫的,有各類版本的,不過我想到給容納方塊運動範圍的數組加個虛擬邊框,就從新回到本身的代碼中來,不過沒實現本身想要的結果,主要仍是本身思路不夠清晰,因而就繼續原來的思路開始寫,用了幾個小時,差很少寫出了一個完整版本。不過仍是有點小bug,而後又回到找bug的過程,找bug比寫代碼蛋疼多了,因而就經過運行來發現各類錯誤,那些檢測函數寫了幾個版本才穩定下來,而後把bug基本消除了,至少沒有發現的bug。也給了一些人測試。而後加上了預覽功能,用的預建立的方法,正在要建立的時候再賦值。若是輸了就給個提示。這個算是穩定版本了。
次日想到給程序加個背景,由於看起來實在是太單調了,因此慢慢實現了加背景的效果。開始的時候方塊都沒有上色,黑白的,測試起來也不方便,等到了穩定了就把顏色給加了上去,不過是單色的,因而又想到怎麼畫不一樣顏色的方塊,想到了用一個二維數組來記錄每個方塊的顏色,這樣就實現了畫不一樣顏色的方塊,玩起來視覺上感受也比較好,慢慢的,想到應該能夠隨時控制是否繼續玩或者暫停,又加了這些功能,主要是對定時器的操做,比較簡單。
那時候是用一個假按鈕,上面寫着開始,暫停,功能也實現了,隨時暫停,隨時繼續,而後總感受缺點啥,哦,聲音,那天晚上不停地找呀,找了很久都沒找到想要的聲音,最後我在想,我玩那個百度應用的俄羅斯方塊的時候,沒網絡的時候能繼續玩,那它的聲音確定在我本地有緩存,翻了半天沒找到任何wav或者mp3之類的音樂文件。最後我一個網頁一個網頁的打開,把目標鎖定到那個swf文件。而後把那個wav文件給提取出來了。內心仍是挺happy的。丫的,此時已經是11點了。關機睡覺。
今天下午就想着,這處理按鍵的消息處理函數太過複雜,就想着重寫之前的那些碰撞檢測函數。對比那個方塊類,寫的時間花的比較少,主要仍是測試,
之因此要重寫,是由於我發現上個版本用的那改變形狀的檢測函數用的方法比較好,應該算是對比法了,因而就想着用這個方法實現其它的碰撞檢測函數。少了許多函數調用,時間也天然少了些。而後按鍵消息處理函數比之前少了一半的代碼量,並且實現起來容易,維護起來也方便很多,不須要在按鍵消息處理函數裏面檢測是否越界,由於用了那個虛擬邊界,這樣就實現了與方塊活動範圍的無關性,更有可複用性。檢測沒問題後,就把動態建立的按鈕加了上去,由於mfc提供的CButton實在是在uglily。到此過程基本就算是最終的版本了。這個是運行截圖linux
這裏貼出部分代碼。數組
方塊類的數據結構和函數
緩存
#ifndef BLOCK_H #define BLOCK_H typedef struct blcokinfo { int type; //方塊的種類 int direction; //方塊的方向 char block[4][4]; //方塊所佔用的矩陣範圍 int cx; //方塊所在4*4矩陣左上角距離邊框14*10矩陣的橫向距離 int cy; //...縱座標 }BLOCKINFO; class CBlock { private: BLOCKINFO m_block; public: void InitBlock(); void SetBlock(); void GetBlock(BLOCKINFO &bl); void ChangeBlock(); public: CBlock& operator=(const CBlock &b); int GetCx(); int GetCy(); int GetType(); int GetDirection(); }; #endif
這個是隨機產生方塊網絡
void CBlock::SetBlock() { int i; srand(time(NULL)); InitBlock(); m_block.type = rand() % 7 + 1; //隨機產生1-7類型的方塊 m_block.direction= 1; m_block.cx = 3; m_block.cy = 0; //具體方塊也不知道叫啥名字,用編號表示,具體是按照本身畫的一個圖紙來的 switch (m_block.type) { //對具體的初始方向爲上的方塊賦值, case 1: for (i = 0; i < 4; i++) { m_block.block[0][i] = 1; } break; case 2: m_block.block[1][1] = 1; for (i = 0; i < 3; i++) { m_block.block[0][i] = 1; } break; case 3: for (i = 0; i < 2; i++) { m_block.block[0][i+1] = 1; m_block.block[1][i] = 1; } break; case 4: for (i = 0; i < 2; i++) { m_block.block[0][i] = 1; m_block.block[1][i+1] = 1; } break; case 5: for (i = 0; i < 2; i++) { m_block.block[i][1] = 1; m_block.block[i][2] = 1; } break; case 6: m_block.block[1][2] = 1; for (i = 0; i < 3; i++) { m_block.block[0][i] = 1; } break; case 7: m_block.block[1][0] = 1; for (i = 0; i < 3; i++) { m_block.block[0][i] = 1; } break; } }
其它幾個函數也是相似的。
由於方塊在4*4這個矩陣裏面變換活動,這個是不變的,因此任什麼時候候只要知道這個矩陣相對與那個大矩陣的橫縱座標就能夠判斷方塊是具體某個地方了。數據結構
而後下面這個函數是CTetrisView類左方向的碰撞檢測函數。 app
BOOL CTetrisView::CheckLeft() { char compareBlock[4][5]; int i, j; for (i = 0; i < 4; i++) {//把14*10矩陣裏方塊活動範圍記下來 for (j = -1; j < 4; j++) {//縱座標向左平移一個單位 compareBlock[i][j+1] = m_region[m_nCy+i][m_nCx+j]; } } switch (m_bl.GetType()) { case 1: if (m_bl.GetDirection() == 2 || m_bl.GetDirection() == 4) {//改變後 for (i = 0; i < 4; i++) { if (compareBlock[i][1] == 1) { return TRUE; } } return FALSE; } else { if (compareBlock[0][0] == 1) {//有障礙 return TRUE; } return FALSE; } break; case 2: if (m_bl.GetDirection() == 1) { if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 2) { if (compareBlock[0][1] == 1) { return TRUE; } if (compareBlock[1][0] == 1) { return TRUE; } if (compareBlock[2][1] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 3) { if (compareBlock[0][1] == 1) { return TRUE; } if (compareBlock[1][0] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 4) { for (i = 0; i < 3; i++) { if (compareBlock[i][1] == 1) { return TRUE; } } return FALSE; } break; case 3: if (m_bl.GetDirection() == 2 || m_bl.GetDirection() == 4) { if (compareBlock[0][1] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } if (compareBlock[2][2] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 1 || m_bl.GetDirection() == 3) { if (compareBlock[1][0] == 1) { return TRUE; } if (compareBlock[0][1] == 1) { return TRUE; } return FALSE; } break; case 4: if (m_bl.GetDirection() == 2 || m_bl.GetDirection() == 4) { if (compareBlock[0][2] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } if (compareBlock[2][1] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 1 || m_bl.GetDirection() == 3) { if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } return FALSE; } break; case 5: if (compareBlock[0][1] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } return FALSE; break; case 6: if (m_bl.GetDirection() == 1) { if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][2] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 2){ if (compareBlock[0][1] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } if (compareBlock[2][0] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 3){ if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][0] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 4){ for (i = 0; i < 3; i++) { if (compareBlock[i][1]) { return TRUE; } } return FALSE; } break; case 7: if (m_bl.GetDirection() == 1) { if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][0] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 2){ if (compareBlock[0][0] == 1) { return TRUE; } if (compareBlock[1][1] == 1) { return TRUE; } if (compareBlock[2][1] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 3){ if (compareBlock[1][0] == 1) { return TRUE; } if (compareBlock[0][2] == 1) { return TRUE; } return FALSE; } else if (m_bl.GetDirection() == 4){ for (i = 0; i < 3; i++) { if (compareBlock[i][1] == 1) { return TRUE; } } return FALSE; } break; } return FALSE; }
檢測函數寫好後就是一些程序邏輯處理的問題和繪圖的問題,繪圖的時候主要注意gdi函數
是稀缺資源,不用了要選回來,create的要delete,其它的我就很少說了。你能夠看個人測試
源代碼。要說的太多了,還不如你本身去實現了,每一個人的想法都是不一樣的,可是異曲同工,spa
達到相同的效果,效率又高,這就夠了。我把俄羅斯方塊的源代碼放在資源裏面了,.net
須要的話能夠去下載看看,另外實現qq那種增長難度的效果也是幾十行代碼的問題。
有興趣的能夠去試試。