C語言圖形程式設計--俄羅斯方塊製作(二)原始碼
阿新 • • 發佈:2019-02-10
所有原始碼檔案,此為本人2年前所作,設計上還有些缺陷。希望大家不吝指正。
下面是標頭檔案head.h
/************************ (C) COPYRIGHT 2013 yang_yulei ************************ * File Name : head.h * Author : yang_yulei * Date First Issued : 12/18/2013 * Description : * * *******************************************************************************/ /* Define to prevent recursive inclusion -------------------------------------*/ #ifndef _HEAD_H_ #define _HEAD_H_ /* Includes ------------------------------------------------------------------*/ #include <graphics.h> #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> /* Macro ---------------------------------------------------------------------*/ #define TRUE 1 #define FALSE 0 //GUI遊戲介面相關的引數 #define GUI_WALL_SQUARE_WIDTH 10 //外圍圍牆小方格的寬度(單位:畫素) #define GUI_xWALL_SQUARE_NUM 30 //橫向(x軸方向)圍牆小方格的數量(必須是偶數) #define GUI_yWALL_SQUARE_NUM 46 //縱向(y軸方向)圍牆小方格的數量(必須是偶數) #define GUI_WALL_WIDTH_PIX (GUI_WALL_SQUARE_WIDTH*GUI_xWALL_SQUARE_NUM) #define GUI_WALL_HIGH_PIX (GUI_WALL_SQUARE_WIDTH*GUI_yWALL_SQUARE_NUM) #define WINDOW_WIDTH 480 //視窗的寬度 #define WINDOW_HIGH GUI_WALL_HIGH_PIX //視窗高度 //俄羅斯方塊相關的引數 //移動的方向 #define DIRECT_UP 3 #define DIRECT_DOWN 2 #define DIRECT_LEFT -1 #define DIRECT_RIGHT 1 //每一個小方塊的大小(是圍牆小方格寬度的2倍) #define ROCK_SQUARE_WIDTH (2*GUI_WALL_SQUARE_WIDTH) //橫向能容納小方格的數量 #define X_ROCK_SQUARE_NUM ((GUI_xWALL_SQUARE_NUM-2)/2) //縱向能容納小方格的數量 #define Y_ROCK_SQUARE_NUM ((GUI_yWALL_SQUARE_NUM-2)/2) /* Exported types ------------------------------------------------------------*/ typedef int BOOL ; //布林值型別 /*資料結構-線性表(結構體陣列)*/ typedef struct ROCK { //用來表示方塊的形狀(每一個位元組是8位,用每4位表示方塊中的一行) unsigned int rockShapeBits ; int nextRockIndex ; //下一個方塊,在陣列中的下標 } RockType ; //方塊在圖形視窗中的位置(即定位4*4大塊的左上角座標) typedef struct LOCATE { int left ; int top ; } RockLocation_t ; /* Function prototypes -------------------------------------------------------*/ //原始檔play.c中 void PlayGame(void) ; //原始檔init.c中 int InitProcParameters(void) ; //原始檔GUI.c中 void DrawRock(int, const struct LOCATE *, BOOL) ; void DrawGameGUI(void) ; void UpdataScore(void) ; void UpdataGrade(int) ; #endif /* _HEAD_H_ */ /*********************** (C) COPYRIGHT 2013 yang_yulei *********END OF FILE****/
下面是原始檔main.cpp
下面是原始檔init.cpp---遊戲執行前 初始化的一些方法/************************ (C) COPYRIGHT 2013 yang_yulei ************************ * File Name : main.cpp * Author : yang_yulei * Date First Issued : 1/16/2012 * Description : 開發環境 VC++ 6.0 含EasyX圖形庫(http://www.easyx.cn) * 俄羅斯方塊 * * ******************************************************************************** * History: * 1/16/2012 : V0.1 * 12/18/2013 : V0.2 ******************************************************************************** * *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "head.h" #include <windows.h> #include <dos.h> /* Typedef -------------------------------------------------------------------*/ /* Variables -----------------------------------------------------------------*/ //全域性變數-遊戲板的狀態描述(即表示當前介面哪些位置有方塊) //0表示沒有,1表示有(多加了兩行和兩列,形成一個圍牆,便於判斷方塊是否能夠移動) char g_gameBoard[Y_ROCK_SQUARE_NUM+2][X_ROCK_SQUARE_NUM+2] = {0} ; //統計分數 int g_score = 0 ; //等級 int g_grade = 0 ; int g_rockTypeNum = 0 ; //共有多少種俄羅斯方塊 RockType rockArray[50] = {(0,0)} ; /******************************************************************************* * Function Name : main * Description : Main program * Input : None * Output : None * Return : None *******************************************************************************/ int main(void) { //畫出遊戲介面 initgraph(WINDOW_WIDTH, WINDOW_HIGH) ; //初始化圖形視窗 cleardevice() ; DrawGameGUI() ; //使用 API 函式修改視窗名稱 HWND hWnd = GetHWnd(); SetWindowText(hWnd, "俄羅斯方塊"); //初始化引數 InitProcParameters() ; //遊戲過程 PlayGame() ; closegraph() ; return 0 ; }
下面是原始檔GUI.cpp---一些關於在介面上畫出介面的一些方法/************************ (C) COPYRIGHT 2013 yang_yulei ************************ * File Name : init.cpp * Author : yang_yulei * Date First Issued : 12/18/2013 * Description : * ******************************************************************************** * *******************************************************************************/ /* Includes ------------------------------------------------------------------*/ #include "head.h" /* Variables -----------------------------------------------------------------*/ extern char g_gameBoard[][X_ROCK_SQUARE_NUM+2] ; extern int g_rockTypeNum ; extern RockType rockArray[] ; /* Function prototypes -------------------------------------------------------*/ static int ReadRockShape(void) ; static unsigned int ShapeStr2uInt(char* const); /******************************************************************************* * Function Name : InitProcParameters * Description : 在正式開始運行遊戲前,初始化一些引數:g_gameBoard 從配置檔案中讀取系統中俄羅斯方塊的形狀 * Be called : main * Input : None * Output : g_gameBoard rockArray * Return : None *******************************************************************************/ //初始化程式引數 int InitProcParameters(void) { int i ; //初始化遊戲板(把這個二維陣列的四周置1,當作圍牆,用於判斷邊界) for (i = 0; i < X_ROCK_SQUARE_NUM+2; i++) { g_gameBoard[0][i] = 1 ; g_gameBoard[Y_ROCK_SQUARE_NUM+1][i]= 1 ; } for (i = 0; i < Y_ROCK_SQUARE_NUM+2; i++) { g_gameBoard[i][0] = 1 ; g_gameBoard[i][X_ROCK_SQUARE_NUM+1]= 1 ; } //從配置檔案中讀取遊戲中所有方塊的形狀點陣 ReadRockShape() ; return 0 ; } /******************************************************************************* * Function Name : ReadRockShape * Description : 從配置檔案中讀取系統中俄羅斯方塊的形狀 把它記錄在rockArray中 * Be called : InitProcParameters * Input : rockshape.ini * Output : rockArray * Return : 成功返回0 失敗返回1 *******************************************************************************/ int ReadRockShape(void) { FILE* fp ; int i = 0 ; int len = 0 ; int rockArrayIdx = 0 ; int shapeNumPerRock = 0 ; //一種方塊的形態數目(用於計算方塊的nextRockIndex) char rdBuf[128] ; char rockShapeBitsStr[128] = {0}; unsigned int shapeBits = 0 ; g_rockTypeNum = 0 ; //開啟配置檔案 從中讀取方塊的形狀 fp = fopen(".\\rockshape.ini", "r") ; if (fp == NULL) { perror("open file error!\n") ; return 1 ; } while (fgets(rdBuf, 128, fp) != NULL) { len = strlen(rdBuf) ; rdBuf[len-1] = '\0' ; switch (rdBuf[0]) { case '@': case '#': strcat(rockShapeBitsStr, rdBuf) ; break ; case 0 : //一個方塊讀取結束 shapeBits = ShapeStr2uInt(rockShapeBitsStr) ; rockShapeBitsStr[0] = 0 ; shapeNumPerRock++ ; rockArray[rockArrayIdx].rockShapeBits = shapeBits ; rockArray[rockArrayIdx].nextRockIndex = rockArrayIdx + 1 ; rockArrayIdx++ ; g_rockTypeNum++ ; //記錄方塊數量的全域性變數+1 break ; case '-'://一種方塊讀取結束(更新其nextRockIndex值) rockArray[rockArrayIdx-1].nextRockIndex = rockArrayIdx - shapeNumPerRock ; shapeNumPerRock = 0 ; break ; default : break ; } }//while() return 0 ; } /******************************************************************************* * Function Name : ShapeStr2uInt * Description : 把配置檔案中的描述方塊形狀的字串 轉化為 unsigned int型 * Be called : * Input : shapeStr 描述方塊形狀的字串(從檔案中讀取的) * Output : None * Return : unsigned int型的方塊形狀點陣(用其低16位表示) *******************************************************************************/ unsigned int ShapeStr2uInt(char* const shapeStr) { unsigned int shapeBitsRet = 0 ; char* p = shapeStr ; for (p += 15; p >= shapeStr; p--) { if (*p == '@') { shapeBitsRet |= ((unsigned int)1 << (&shapeStr[15]-p)) ; } } return shapeBitsRet ; }
/************************ (C) COPYRIGHT 2013 yang_yulei ************************
* File Name : GUI.cpp
* Author : yang_yulei
* Date First Issued : 12/18/2013
* Description :
*
********************************************************************************
*
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "head.h"
/* Variables -----------------------------------------------------------------*/
//預覽區位置
RockLocation_t previewLocation = {GUI_WALL_SQUARE_WIDTH*GUI_xWALL_SQUARE_NUM+70, 50} ;
extern RockType rockArray[] ;
/*******************************************************************************
* Function Name : DrawRock
* Description : 在遊戲區畫出編號為rockIndex的方塊
* Be called : PlayGame()
* Input : rockIndex :
currentLocatePtr: 此方塊的位置
displayed : 此方塊是否顯示
* Output : None
* Return : None
*******************************************************************************/
void
DrawRock(int rockIndex, const struct LOCATE * currentLocatePtr, BOOL displayed)
{
int i ;
int mask ;
int rockX ; //俄羅斯方塊的4*4模型的左上角點x軸的座標
int rockY ; //俄羅斯方塊的4*4模型的左上角點y軸的座標
int spaceFlag ; //佔位標記(用於g_gameBoard,1表示某處有方塊 0表示此處無方塊)
int color ; //畫出的方塊的顏色
//若此方塊是用於顯示的,則設定其顏色為白色,其佔位標記設為1
//否則設定其顏色為黑色(背景色),佔位標記設為0
displayed ? (color = WHITE,spaceFlag = 1)
: (color = BLACK,spaceFlag = 0) ;
setcolor(color) ; //設定畫筆顏色
setlinestyle(PS_SOLID, NULL, 2) ; //設定線形為1畫素的實線
rockX = currentLocatePtr->left ;
rockY = currentLocatePtr->top ;
//逐位掃描由unsigned int的低2位元組
//16個位組成的俄羅斯方塊形狀點陣(其代表4*4的方塊形狀)
mask = (unsigned int)1 << 15 ;
for (i=1; i<=16; i++)
{
//與掩碼相與為1的 即為方塊上的點
if ((rockArray[rockIndex].rockShapeBits & mask) != 0)
{
//在螢幕上畫出此方塊
rectangle(rockX+2,
rockY+2,
rockX+ROCK_SQUARE_WIDTH-2,
rockY+ROCK_SQUARE_WIDTH-2) ;
}
//每4次 換行 轉到下一行繼續畫
i%4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH ;
mask >>= 1 ;
}
}
/*******************************************************************************
* Function Name : DrawGameGUI
* Description : 畫出遊戲介面
* Be called : main()
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void
DrawGameGUI(void)
{
int i = 0 ;
int wallHigh = GUI_yWALL_SQUARE_NUM * GUI_WALL_SQUARE_WIDTH ;//圍牆的高度(畫素)
setcolor(RED) ; //設定圍牆的顏色
setlinestyle(PS_SOLID, NULL, 0) ; //設定圍牆方格的線形(1畫素的實線)
//畫出圍牆(畫矩形是 先確定左上頂點的座標,再確定右下頂點座標)
//先畫出上下牆
for (i = GUI_WALL_SQUARE_WIDTH;
i <= GUI_WALL_WIDTH_PIX;
i += GUI_WALL_SQUARE_WIDTH)
{
rectangle(i-GUI_WALL_SQUARE_WIDTH,
0,
i,
GUI_WALL_SQUARE_WIDTH) ; //上牆
rectangle(i-GUI_WALL_SQUARE_WIDTH,
wallHigh-GUI_WALL_SQUARE_WIDTH,
i,
wallHigh) ; //下牆
}
//再畫出左右牆
for (i = 2*GUI_WALL_SQUARE_WIDTH;
i <= wallHigh-GUI_WALL_SQUARE_WIDTH;
i += GUI_WALL_SQUARE_WIDTH)
{
rectangle(0,
i-GUI_WALL_SQUARE_WIDTH,
GUI_WALL_SQUARE_WIDTH,
i) ; //左牆
rectangle(GUI_WALL_WIDTH_PIX-GUI_WALL_SQUARE_WIDTH,
i-GUI_WALL_SQUARE_WIDTH,
GUI_WALL_WIDTH_PIX,
i) ; //右牆
}
//畫分隔線
setcolor(WHITE) ; //設定畫筆顏色
setlinestyle(PS_DASH, NULL, 2) ; //設定線形為2畫素的虛線
line(GUI_WALL_WIDTH_PIX+20,0,GUI_WALL_WIDTH_PIX+20,wallHigh) ; //在偏移右圍牆的20處畫線
//畫右邊統計分數及版權資訊欄
//先設定字型
LOGFONT f ; //定義字型屬性結構體
getfont(&f) ; //獲得當前字型
f.lfHeight = 18 ; //設定字型高度為 38(包含行距)
strcpy(f.lfFaceName, "黑體") ; //設定字型為“黑體”
f.lfQuality = ANTIALIASED_QUALITY ; //設定輸出效果為抗鋸齒
setfont(&f) ; //設定字型樣式
//1,顯示預覽
outtextxy(GUI_WALL_WIDTH_PIX+80 , 20 , "預覽") ;
//2,顯示等級欄
outtextxy(GUI_WALL_WIDTH_PIX+80 , 140 , "等級") ;
//3,顯示得分欄
outtextxy(GUI_WALL_WIDTH_PIX+80 , 190 , "得分") ;
//4,顯示操作說明
outtextxy(GUI_WALL_WIDTH_PIX+65 , 255 , "操作說明") ;
getfont(&f) ;
strcpy(f.lfFaceName, "宋體") ;
f.lfHeight = 15 ;
setfont(&f) ;
outtextxy(GUI_WALL_WIDTH_PIX+45 , 290 , "w.a.s.d控制方向") ;
outtextxy(GUI_WALL_WIDTH_PIX+45 , 313 , "回車鍵 暫停") ;
outtextxy(GUI_WALL_WIDTH_PIX+45 , 336 , "空格鍵 快速下落") ;
//5.版權資訊
line(GUI_WALL_WIDTH_PIX+20 , wallHigh-65 , WINDOW_WIDTH , wallHigh-65) ;
outtextxy(GUI_WALL_WIDTH_PIX+40 , wallHigh-50 , " 楊溢之 作品") ;
outtextxy(GUI_WALL_WIDTH_PIX+40 , wallHigh-30 , " QQ:702080167") ;
//顯示等級,得分資訊
setcolor(RED) ;
outtextxy(GUI_WALL_WIDTH_PIX+90 , 163 , "1") ;
outtextxy(GUI_WALL_WIDTH_PIX+90 , 223 , "0") ;
}
/*******************************************************************************
* Function Name : UpdataScore
* Description : 增加一次得分,並把遊戲介面的得分割槽顯示 更新
* Be called : ProcessFullRow()
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void
UpdataScore(void)
{
char scoreStr[5] ; //用字串的形式儲存得分
extern int g_score ;
extern int g_grade ;
//分數的增長的單位是10
g_score += 10 ;
//得分是100的倍數,則等級加1 (等級在5級以上的就 保持不變)
if (g_score == (g_score/100)*100 && g_grade < 5)
UpdataGrade(++g_grade) ;
//刪除原先資訊
setfillstyle(BLACK) ;
bar(GUI_WALL_WIDTH_PIX+90,220,GUI_WALL_WIDTH_PIX+99,229) ;
//顯示資訊
setcolor(RED) ;
sprintf(scoreStr , "%d" , g_score) ;
outtextxy(GUI_WALL_WIDTH_PIX+90 , 223 , scoreStr) ;
}
/*******************************************************************************
* Function Name : UpdataGrade
* Description : 增加一次等級,並把遊戲介面的等級區顯示 更新
* Be called :
* Input : grade :新的等級值
* Output : None
* Return : None
*******************************************************************************/
void
UpdataGrade(int grade)
{
char gradeStr[5] ;
//刪除原先資訊
setfillstyle(BLACK) ;
bar(GUI_WALL_WIDTH_PIX+90,160,GUI_WALL_WIDTH_PIX+99,169) ;
//顯示資訊
setcolor(RED) ;
sprintf(gradeStr , "%d" , grade) ;
outtextxy(GUI_WALL_WIDTH_PIX+90 , 163 , gradeStr) ;
}
下面是原始檔play.cpp---控制遊戲的重要方法/************************ (C) COPYRIGHT 2013 yang_yulei ************************
* File Name : play.cpp
* Author : yang_yulei
* Date First Issued : 12/18/2013
* Description :
*
********************************************************************************
*
*******************************************************************************/
/* Includes ------------------------------------------------------------------*/
#include "head.h"
/* Variables -----------------------------------------------------------------*/
extern char g_gameBoard[][X_ROCK_SQUARE_NUM+2] ;
extern int g_rockTypeNum ;
extern RockType rockArray[] ;
/* Function prototypes -------------------------------------------------------*/
static BOOL MoveAble(int, const struct LOCATE *, int) ;
static void SetOccupyFlag(int, const struct LOCATE *) ;
static void ProcessFullRow(void) ;
static BOOL isGameOver() ;
static void ProccessUserHit(int, int*, struct LOCATE*) ;
static void FastFall(int, struct LOCATE *, struct LOCATE *) ;
static void DelFullRow(int f_row) ;
/*******************************************************************************
* Function Name : PlayGame
* Description : 此程式的主要設計邏輯
* Be called : main
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void
PlayGame(void)
{
int userHitChar ; //使用者敲擊鍵盤的字元
int currentRockIndex ; //當前方塊在rockArray陣列中下標
int nextRockIndex ; //準備的下個方塊的下標
BOOL moveAbled = FALSE ;//記錄方塊能否落下
DWORD oldtime = 0;
extern int g_grade ;
//當前方塊位置
RockLocation_t currentRockLocation ;
//初始方塊位置(由當中開始下落)
RockLocation_t initRockLocation = {(GUI_xWALL_SQUARE_NUM/2-4)*GUI_WALL_SQUARE_WIDTH,
GUI_WALL_SQUARE_WIDTH};
//預覽區位置
extern RockLocation_t previewLocation ;
//為第一次下落,初始化引數
//隨機選擇當前的俄羅斯方塊形狀 和下一個俄羅斯方塊形狀
srand(time(NULL)) ;
currentRockIndex = rand()%g_rockTypeNum ;
nextRockIndex = rand()%g_rockTypeNum ;
currentRockLocation.left = initRockLocation.left ;
currentRockLocation.top = initRockLocation.top ;
while(1)
{
DrawRock(currentRockIndex, ¤tRockLocation, TRUE) ;
FlushBatchDraw(); //用批繪圖功能,可以消除閃爍
//判斷能否下落
moveAbled = MoveAble(currentRockIndex, ¤tRockLocation, DIRECT_DOWN) ;
//如果不能下落則生成新的方塊
if (!moveAbled)
{
//設定佔位符(此時方塊已落定)
SetOccupyFlag(currentRockIndex, ¤tRockLocation) ;
//擦除預覽
DrawRock( nextRockIndex, &previewLocation, FALSE) ;
//生成新的方塊
currentRockIndex = nextRockIndex ;
nextRockIndex = rand()%g_rockTypeNum ;
currentRockLocation.left = initRockLocation.left ;
currentRockLocation.top = initRockLocation.top ;
}
//顯示預覽
DrawRock(nextRockIndex, &previewLocation, TRUE) ;
//如果超時(且能下落),自動下落一格
// 這個超時時間400-80*g_grade 是本人根據實驗自己得出的
// 一個速度比較適中的一個公式(g_grade不會大於等於5)
DWORD newtime = GetTickCount();
if (newtime - oldtime >= (unsigned int)(400-80*g_grade) && moveAbled == TRUE)
{
oldtime = newtime ;
DrawRock(currentRockIndex, ¤tRockLocation, FALSE) ; //擦除原先位置
currentRockLocation.top += ROCK_SQUARE_WIDTH ; //下落一格
}
//根據當前遊戲板的狀況判斷是否滿行,並進行滿行處理
ProcessFullRow() ;
//判斷是否遊戲結束
if (isGameOver())
{
MessageBox( NULL,"遊戲結束", "GAME OVER", MB_OK ) ;
exit(0) ;
}
//測試鍵盤是否被敲擊
if (kbhit())
{
userHitChar = getch() ;
ProccessUserHit(userHitChar, ¤tRockIndex, ¤tRockLocation) ;
}
Sleep(20) ; //降低CPU使用率
}//結束外層while(1)
}
/*******************************************************************************
* Function Name : ProccessUserHit
* Description : 處理使用者敲擊鍵盤
* Be called : PlayGame()
* Input : userHitChar 使用者敲擊鍵盤的ASCII碼
rockIndexPtr 當前俄羅斯方塊在rockArray中的下標
rockLocationPtr 當前方塊在遊戲介面中的位置
* Output : rockIndexPtr 響應使用者敲擊後 新方塊的下標
rockLocationPtr 響應使用者敲擊後 新方塊的位置
* Return : None
*******************************************************************************/
void
ProccessUserHit(int userHitChar, int* rockIndexPtr, struct LOCATE* rockLocationPtr)
{
switch (userHitChar)
{
case 'w' : case 'W' : //“上”鍵
//檢查是否能改變方塊形狀
if (MoveAble(rockArray[*rockIndexPtr].nextRockIndex, rockLocationPtr, DIRECT_UP))
{
DrawRock(*rockIndexPtr, rockLocationPtr, FALSE) ;
*rockIndexPtr = rockArray[*rockIndexPtr].nextRockIndex ;
}
break ;
case 's' : case 'S' : //“下”鍵
DrawRock(*rockIndexPtr, rockLocationPtr, FALSE) ; //擦除原先位置
rockLocationPtr->top += ROCK_SQUARE_WIDTH ;
break ;
case 'a' : case 'A' : //“左”鍵
if (MoveAble(*rockIndexPtr, rockLocationPtr, DIRECT_LEFT))
{
DrawRock(*rockIndexPtr, rockLocationPtr, FALSE) ;
rockLocationPtr->left -= ROCK_SQUARE_WIDTH ;
}
break ;
case 'd' : case 'D' : //“右”鍵
if (MoveAble(*rockIndexPtr, rockLocationPtr, DIRECT_RIGHT))
{
DrawRock(*rockIndexPtr, rockLocationPtr, FALSE) ;
rockLocationPtr->left += ROCK_SQUARE_WIDTH ;
}
break ;
case ' ' : //空格(快速下落)
DrawRock(*rockIndexPtr, rockLocationPtr, FALSE) ;
FastFall(*rockIndexPtr, rockLocationPtr, rockLocationPtr) ;
break ;
case 13 : //回車鍵(暫停)
while(1)
{ userHitChar = getch() ;
if (userHitChar==13)
break ;
}
break ;
default :
break ;
}
}
/*******************************************************************************
* Function Name : MoveAble
* Description : 判斷編號為rockIndex 在位置currentLocatePtr的方塊
能否向direction移動
* Be called :
* Input : None
* Output : None
* Return : TRUE 可以移動
FALSE 不可以移動
*******************************************************************************/
BOOL
MoveAble(int rockIndex, const struct LOCATE* currentLocatePtr, int f_direction)
{
int i ;
int mask ;
int rockX ;
int rockY ;
rockX = currentLocatePtr->left ;
rockY = currentLocatePtr->top ;
mask = (unsigned int)1 << 15 ;
for (i=1; i<=16; i++)
{
//與掩碼相與為1的 即為方塊上的點
if ((rockArray[rockIndex].rockShapeBits & mask) != 0)
{
//判斷能否移動(即掃描即將移動的位置 是否與設定的圍牆有重疊)
//若是向上(即翻滾變形)
if( f_direction == DIRECT_UP )
{
//因為此情況下傳入的是下一個方塊的形狀,故我們直接判斷此方塊的位置是否已經被佔
if (g_gameBoard[(rockY-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]
[(rockX-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] == 1)
return FALSE ;
}
//如果是向下方向移動
else if( f_direction == DIRECT_DOWN )
{
if (g_gameBoard[(rockY-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+2]
[(rockX-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] ==1)
return FALSE ;
}
else //如果是左右方向移動
{ //f_direction的DIRECT_LEFT為-1,DIRECT_RIGHT為1,故直接加f_direction即可判斷。
if (g_gameBoard[(rockY-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]
[(rockX-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1+f_direction] ==1)
return FALSE ;
}
}
//每4次 換行 轉到下一行繼續
i%4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH ;
mask >>= 1 ;
}
return TRUE ;
}
/*******************************************************************************
* Function Name : SetOccupyFlag
* Description : 更新遊戲板狀態(把一些位置設定為已佔用)
* Be called :
* Input : rockIndex 方塊的下標(定位了方塊的形狀)
currentLocatePtr 方塊的位置(用來設定已佔用標識)
* Output : None
* Return : None
*******************************************************************************/
void
SetOccupyFlag(int rockIndex, const struct LOCATE * currentLocatePtr)
{
int i ;
int mask ;
int rockX ;
int rockY ;
rockX = currentLocatePtr->left ;
rockY = currentLocatePtr->top ;
mask = (unsigned int)1 << 15 ;
for (i=1; i<=16; i++)
{
//與掩碼相與為1的 即為方塊上的點
if ((rockArray[rockIndex].rockShapeBits & mask) != 0)
{
g_gameBoard[(rockY-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]
[(rockX-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] = 1 ;
}
//每4次 換行 轉到下一行繼續畫
i%4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH ;
mask >>= 1 ;
}
}
/*******************************************************************************
* Function Name : ProcessFullRow
* Description : 檢查是否有滿行,若有,則刪除滿行(並更新得分資訊)
* Be called :
* Input : g_gameBoard
* Output : None
* Return : None
*******************************************************************************/
void
ProcessFullRow(void)
{
int i = 1 ;
int cnt = 0 ;
BOOL rowFulled = TRUE ;
int rowIdx = Y_ROCK_SQUARE_NUM ; //從最後一行開始往上檢查
while (cnt != X_ROCK_SQUARE_NUM) //直到遇到是空行的為止
{
rowFulled = TRUE ;
cnt = 0 ;
//判斷是否有滿行 並消除滿行
for (i = 1; i <= X_ROCK_SQUARE_NUM; i++)
{
if( g_gameBoard[rowIdx][i] == 0 )
{
rowFulled = FALSE ;
cnt++ ;
}
}
if (rowFulled) //有滿行 (並更新得分資訊)
{
DelFullRow(rowIdx) ;
//更新得分資訊
UpdataScore() ;
rowIdx++ ;
}
rowIdx-- ;
}
}
/*******************************************************************************
* Function Name : DelFullRow
* Description : 刪除遊戲板的第rowIdx行
* Be called :
* Input : g_gameBoard
rowIdx 要刪除的行 在g_gameBoard中的下標
* Output : None
* Return : None
*******************************************************************************/
void
DelFullRow(int rowIdx)
{
int cnt = 0 ;
int i ;
//把此行擦除
setcolor(BLACK) ;
for (i=1; i<=X_ROCK_SQUARE_NUM; i++)
{
rectangle(GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx-2) ;
}
//把此行之上的遊戲板方塊全向下移動一個單位
while (cnt != X_ROCK_SQUARE_NUM) //直到遇到是空行的為止
{
cnt =0 ;
for (i=1; i<=X_ROCK_SQUARE_NUM; i++)
{
g_gameBoard[rowIdx][i] = g_gameBoard[rowIdx-1][i] ;
//擦除上面的一行
setcolor(BLACK) ;
rectangle( GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*(rowIdx-1)-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*(rowIdx-1)-2 ) ;
//顯示下面的一行
if (g_gameBoard[rowIdx][i] ==1)
{
setcolor(WHITE) ;
rectangle( GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx-ROCK_SQUARE_WIDTH+2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*i-2,
GUI_WALL_SQUARE_WIDTH+ROCK_SQUARE_WIDTH*rowIdx-2 ) ;
}
if (g_gameBoard[rowIdx][i] == 0)
cnt++ ; //統計一行是不是 都是空格
}//for
rowIdx-- ;
}
}
/*******************************************************************************
* Function Name : FastFall
* Description : 讓編號為rockIndex 且初始位置在currentLocatePtr的方塊
快速下落到底部
* Be called :
* Input : rockIndex currentLocatePtr
* Output : endLocatePtr 下落後方塊的位置
* Return : None
*******************************************************************************/
void
FastFall
(int rockIndex,
struct LOCATE * currentLocatePtr,
struct LOCATE * endLocatePtr)
{
int i ;
int mask ; //掩碼,用於判斷方塊的形狀
int rockX ; //方塊的座標(4*4方格的左上角點的x軸座標)
int rockY ; //方塊的座標(4*4方格的左上角點的y軸座標)
while (currentLocatePtr->top <= GUI_WALL_SQUARE_WIDTH+Y_ROCK_SQUARE_NUM*ROCK_SQUARE_WIDTH)
{
rockX = currentLocatePtr->left ;
rockY = currentLocatePtr->top ;
mask = (unsigned int)1 << 15 ;
for (i=1; i<=16; i++)
{
//與掩碼相與為1的 即為方塊上的點
if ((rockArray[rockIndex].rockShapeBits & mask) != 0)
{
if(g_gameBoard[(rockY-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1]
[(rockX-GUI_WALL_SQUARE_WIDTH)/ROCK_SQUARE_WIDTH+1] == 1) //遇到底部
{
endLocatePtr->top = currentLocatePtr->top-ROCK_SQUARE_WIDTH ;
return ;
}
}
//每4次 換行 轉到下一行繼續畫
i%4 == 0 ? (rockY += ROCK_SQUARE_WIDTH, rockX = currentLocatePtr->left)
: rockX += ROCK_SQUARE_WIDTH ;
mask >>= 1 ;
}
currentLocatePtr->top += ROCK_SQUARE_WIDTH ;
}//while()
}
/*******************************************************************************
* Function Name : isGameOver
* Description : 判斷是否遊戲結束
* Be called :
* Input : None
* Output : None
* Return : TRUE 遊戲結束
FALSE 遊戲繼續
*******************************************************************************/
BOOL
isGameOver()
{
int i ;
BOOL topLineHaveRock = FALSE ; //在介面的最高行有方塊的標記
BOOL bottomLineHaveRock = FALSE ; //在介面的最低行有方塊的標記
for (i=1; i<=X_ROCK_SQUARE_NUM; i++)
{
if( g_gameBoard[1][i] == 1 )
topLineHaveRock = TRUE ;
if( g_gameBoard[Y_ROCK_SQUARE_NUM][i] == 1 )
bottomLineHaveRock = TRUE ;
}
//若底層行和頂層行都有方塊 則說明在所有行都有方塊,遊戲結束
if (topLineHaveRock && bottomLineHaveRock)
return TRUE ;
else
return FALSE ;
}
下面是配置檔案rockshape.ini
@###
@###
@@##
####
@@@#
@###
####
####
@@##
#@##
#@##
####
##@#
@@@#
####
####
-----
#@##
#@##
@@##
####
@###
@@@#
####
####
@@##
@###
@###
####
@@@#
##@#
####
####
-----
@###
@@##
#@##
####
#@@#
@@##
####
####
-----
#@##
@@##
@###
####
@@##
#@@#
####
####
-----
#@##
@@@#
####
####
@###
@@##
@###
####
@@@#
#@##
####
####
#@##
@@##
#@##
####
-----
#@##
#@##
#@##
#@##
@@@@
####
####
####
-----
####
@@##
@@##
####
-----