C语言图形编程–俄罗斯方块制作(二)源代码

最后更新于:2022-04-01 20:30:25

所有源代码文件,此为本人2年前所作,设计上还有些缺陷。希望大家不吝指正。 **[设计详解点击这里](http://blog.csdn.net/yang_yulei/article/details/17651737)** ** ** **下面是头文件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 #include #include #include #include /* 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** ~~~ /************(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 #include /* 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 ; } ~~~ **下面是源文件init.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 ; } ~~~ **下面是源文件GUI.cpp---一些关于在界面上画出界面的一些方法** ~~~ /************(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** ~~~ @### @### @@## #### @@@# @### #### #### @@## #@## #@## #### ##@# @@@# #### #### ----- #@## #@## @@## #### @### @@@# #### #### @@## @### @### #### @@@# ##@# #### #### ----- @### @@## #@## #### #@@# @@## #### #### ----- #@## @@## @### #### @@## #@@# #### #### ----- #@## @@@# #### #### @### @@## @### #### @@@# #@## #### #### #@## @@## #@## #### ----- #@## #@## #@## #@## @@@@ #### #### #### ----- #### @@## @@## #### ----- ~~~
';