【C語言】實現俄羅斯方塊
學習了C語言,寫一個俄羅斯方塊,程式碼絕對可以執行
大神勿笑,只適合初學者 本人也是菜鳥
1、考慮怎麼儲存俄羅斯方塊
俄羅斯方塊的形狀一共有19種類型,如果拿陣列來表示的話,可能會比較會浪費空間(網上有很多實現程式碼)
考慮到每種方塊形狀的範圍是4 *4的小方塊,用 字模點陣的方式來儲存,即設定一個4行4列的陣列,元素置1即代表這個位置有小
方塊,元素置0即代表這個位置無小方塊,這個整個的4*4的陣列組成俄羅斯方塊的形狀。
1000
1000
1100
0000
上述4*4來表示L形狀的方塊。
4*4 =16 bit 正好為short型別,所以每一個方塊可以用一個short型別的資料來表示。
我們把俄羅斯方塊點陣的數位存在rockArray中,我們可以事先把這19種方塊的字模點陣自己轉化成十六進位制,然後在rockArray陣列的初始化時賦值進去。
但是這種方式擴充套件性不好,每當有一種新方塊時需要改動,
所以可以寫一個配置檔案來表示19種方塊。(RockShape.ini)
@###
@###
@@##
####
從配置檔案中讀取方塊的型別的程式碼在(Init.h的ReadRock函式中)在下面3中解釋下程式碼如何實現
2如何畫出方塊
可以使用EasyX庫來畫出簡單的圖形,
EasyX庫是在VC下實現TC的簡單繪圖功能的一個庫,這個庫很容易學會(直接 百度EasyX庫,裡面有詳細的教程)
那麼如何畫出方塊,方塊已經儲存到一個short型別中了
從short中讀取出,可以用一個掩碼mask = 1來與short的每個bit位相與,結果為1,則畫出一個小方塊;
函式宣告:
void DisplayRock(int rockIdx, RockLocation_t* LocatePtr, bool displayed)
引數1:表示在陣列中的下標,取出short型別的方塊表示資料
引數2:表示當前座標,即畫出方塊的左上角的座標x,y
引數3:true表示畫出該方塊,false 表示擦除該方塊。
//方塊在圖形視窗中的位置(即定位4*4大塊的左上角座標)
typedef struct LOCATE
{
int left;
int top;
} RockLocation_t;
3如何實現同一種類型方塊的翻轉,
在按‘↑’時應該翻轉同一種類型的方塊,
比如下面的橫杆和豎杆
@###
@###
@###
@###
@@@@
####
####
####
****
可以假想成靜態迴圈連結串列來實現這種方式
使同一種類型的方塊迴圈起來,
用一個struct結構來表示一種方塊
typedef struct ROCK
{
//用來表示方塊的形狀(每一個位元組是8位,用每4位表示方塊中的一行)
unsigned short rockShapeBits;
int nextRockIndex; //下一個方塊,在陣列中的下標
} RockType;
定義一個RockType型別的陣列來儲存19種方塊
RockType RockArray[19] = { (0, 0) };
當我們按“↑”時,把傳入畫方塊函式DrawRock中的rockIndex變為當前方塊結構體中的nextRockIndex即可。
簡單解釋下ReadRock函式的實現:當讀取到空行的時候表示 一種方塊已經讀取完畢,當讀取到**** 行時 表示同一種類型的方塊讀取完畢,具體看程式碼實現,程式碼中具體的註釋
4、主要遊戲實現的邏輯
貼一個預覽圖吧
注:上述預覽圖的遊戲控制區和遊戲顯示區在Draw.h的DrawGameWindow()函式實現的
(1)在初始位置畫出方塊,在預覽區畫出下一次的方塊
(2)方塊有兩種行為:響應鍵盤命令UserHitKeyBoard(),自由下落
如果敲擊鍵盤了(w ,a ,s ,d, )空格表示暫停,如果在規定時間內沒有敲擊鍵盤的話,方塊自由下落一個單位
if (kbhit()) //如果敲擊鍵盤了 就處理按鍵
{
userHit = getch();
UserHitKeyBoard(userHit, &curRockIndex, &curRockLocation);
}
//沒有 就自動下移一個單位 :不能用else,因為可能按鍵不是上下左右
DWORD newtime = GetTickCount();
if (newtime - oldtime >= (unsigned int)(300) && moveAbled == TRUE)
{
oldtime = newtime;
DisplayRock(curRockIndex, &curRockLocation, false);
curRockLocation.top += ROCK_SQUARE_WIDTH; //下落一格
}
(3)當方塊落地(即不能下移了)時,判斷是否滿行,如果滿行則消除,然後再判斷遊戲是否結束,遊戲結束的話,直接退出遊戲
判斷滿行:FullLine()函式,從最底下的一行開始判斷,直到遇到一行空行,
while (count != xROCK_SQUARE_NUM ) //遇到空行 14
{
linefull = true;
count = 0;
for (int i = 1; i <= xROCK_SQUARE_NUM; ++i)
{
if (game_board[idx][i] == 0)
{
linefull = false;
count++;
}
}
if (linefull) //滿行,消除當前行,更新分數
{
DelCurLine(idx);//消除滿行
game_socres += 3;
UpdateSocres(game_socres);
idx++;//因為下面要減1
}
idx--;
}
(4)消除滿行
將要刪除的滿行擦除:即將方塊化成與背景色相同的,該程式碼為黑色
然後將上面的一行向下移,移一行刪除一行,直到遇到空行
具體看程式碼的具體實現 game.h
void DelCurLine(int rowIdx)
(4)判斷方塊是否能移動
在game.h中實現
bool MoveAble(int rockIndex, RockLocation_t* currentLocatePtr, int f_direction)
**比較當前位置的座標(左上角)開始,能否放下rockIndex的方塊。
注:f_direction為”↑”的話,則傳入的rockIndex為下一個方塊**
如果不能移動的話,給遊戲game_board設定標記表示該位置被佔有
//全域性變數-遊戲板的狀態描述(即表示當前介面哪些位置有方塊)
//0表示沒有,1表示有(多加了兩行和兩列,形成一個圍牆,便於判斷方塊是否能夠移動)
int game_board[yROCK_SQUARE_NUM + 2][xROCK_SQUARE_NUM + 2] = { 0 };
實現過程遇到的一些問題
(1)在快速下落的時候,可能方塊會掉出圍牆的範圍內,
快速下落是使方塊每次下落2個單位距離。
在判斷不能下落時,使當前座標的top即y減去一個單位的距離
(2)遇到多行滿行時消除不了,
在判斷滿行時,迴圈找出滿行,找出一個滿行,就消除一行,然後繼續判斷是否滿行,直到遇到空行