俄罗斯方块(Terris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。
当游戏方块左右移动、下落、旋转时,要先清除先前的游戏方块,用新坐标重绘游戏方块
当消除满行时,要重绘游戏底板的当前状态
功能模块介绍
首先初始化OpenGL描画库资源,然后进入的是游戏 欢迎界面,由玩家选择是否进入游戏,或者直接退出。
处理流程如图
功能设计
功能设计
功能设计
功能设计
功能设计
#include<GL/glut.h> #include<time.h> #include<windows.h> #include<stdlib.h> #include<stdio.h> #include<conio.h> #define LEFT 'a'/*操控按键宏定义*/ #define RIGHT 'd' #define UP 'w' #define DOWN 's' #define START 0 #define SIZE 20/*图形范围定义*/ #define ESC 27/*键值定义*/ #define ENTER 13 #define MAX_CHAR 128/*输出文字显示列表数量*/ /*定义光标移动的点*/ struct Point { int x; int y; }; /* 初始化七个二维数组,即七个块刚开始产生时出现的位置 记录坐标的顺序为从左至右,从上至下 */ GLfloat afShape[][4][2] = { { { -0.2f, 0.9f }, { -0.2f, 0.8f }, { -0.2f, 0.7f }, { -0.2f, 0.6f } }, /*1、记录初始下落时长条四个坐标*/ { { -0.3f, 0.9f }, { -0.2f, 0.9f }, { -0.3f, 0.8f }, { -0.2f, 0.8f } }, /*2、记录初始下落时正方形四个坐标*/ { { -0.3f, 0.9f }, { -0.4f, 0.8f }, { -0.3f, 0.8f }, { -0.2f, 0.8f } }, /*3、记录初始下落时T字形四个坐标*/ { { -0.3f, 0.9f }, { -0.2f, 0.9f }, { -0.2f, 0.8f }, { -0.1f, 0.8f } }, /*4、记录初始下落时Z字形四个坐标*/ { { -0.3f, 0.9f }, { -0.2f, 0.9f }, { -0.4f, 0.8f }, { -0.3f, 0.8f } }, /*5、记录初始下落时倒Z字形四个坐标*/ { { -0.3f, 0.9f }, { -0.3f, 0.8f }, { -0.3f, 0.7f }, { -0.2f, 0.7f } }, /*6、记录初始下落时L字形四个坐标*/ { { -0.2f, 0.9f }, { -0.2f, 0.8f }, { -0.3f, 0.7f }, { -0.2f, 0.7f } }, /*7、记录初始下落时倒L字形四个坐标*/ }; GLfloat afShapeNext[][4][2] = { { { 0.7f, 0.7f }, { 0.7f, 0.6f }, { 0.7f, 0.5f }, { 0.7f, 0.4f } }, /*1、记录预览下一长条四个坐标*/ { { 0.6f, 0.7f }, { 0.7f, 0.7f }, { 0.6f, 0.6f }, { 0.7f, 0.6f } }, /*2、记录预览下一正方形四个坐标*/ { { 0.7f, 0.7f }, { 0.6f, 0.6f }, { 0.7f, 0.6f }, { 0.8f, 0.6f } }, /*3、记录预览下一T字形四个坐标*/ { { 0.6f, 0.7f }, { 0.7f, 0.7f }, { 0.7f, 0.6f }, { 0.8f, 0.6f } }, /*4、记录预览下一Z字形四个坐标*/ { { 0.7f, 0.7f }, { 0.8f, 0.7f }, { 0.6f, 0.6f }, { 0.7f, 0.6f } }, /*5、记录预览下一倒Z字形四个坐标*/ { { 0.6f, 0.7f }, { 0.6f, 0.6f }, { 0.6f, 0.5f }, { 0.7f, 0.5f } }, /*6、记录预览下一L字形四个坐标*/ { { 0.7f, 0.7f }, { 0.7f, 0.6f }, { 0.6f, 0.5f }, { 0.7f, 0.5f } }, /*7、记录预览下一倒L字形四个坐标*/ }; /*这里定义的over是用来判断方块是否到达了不能再往下降的地方,到了 则置其为1,否则就修改为0。 其中有这样几种情况需要修改over: 1、重新生成了一个方块,修改over=0 2、方块到大底部,修改over=1*/ GLint aiBlock[SIZE][SIZE] = { 0 };/*记录游戏区域方块状态*/ GLfloat afCurLoc[4][2] = { 0 };/*记录当前正在下落的方块的四个坐标*/ GLfloat afNextLoc[4][2] = { 0 };/*记录接下来下落的方块的四个坐标*/ GLint iCurrentBlock = 1;/*记录当前正在下落的是第1种图形,顺序如上面所示*/ GLint iNextBlock = 1;/*记录接下来下落的是第1种图形,顺序如上面所示*/ GLint aiTurn[7] = { 0 };/*应该变换的形态*/ GLfloat xd = 0.0f, yd = 0.0f; GLuint uiTextFont;/*定义文字输出函数时需用到*/ int iLevel = 0; int iOver = 0; int iEndGame = 0;/*记录游戏是否结束*/ int iScore = 0; int iLefRig = 0; int iTimeS = 1000; int iStart = -1;/*0表示退出游戏,1表示开始游戏*/ char cButton;/*键盘敲下的键值*/ struct Point stPoint; /*函数声明*/ void Down(int id); void InitBlock(void); void Change(void); void CheckDelete(void); int CheckConflict(int iLefRig); void CreateBlocks(void); void BlockDisplay(void); void Key(unsigned char k, int x, int y); void Delete(int *empty); void PrintString(char *s);/*字符打印函数*/ void MenuDisplay(void);/*显示帮助菜单*/ void InitString(void); void GotoXY(int x, int y);/*移动坐标函数*/ void Choose(void); void EndScreen(void); void WelcomeScreen(void); void PrintString(char *s) { if (s == NULL) return; glPushAttrib(GL_LIST_BIT); /*调用每个字符对应的显示列表,绘制每个字符*/ for (; *s != '\0'; ++s) glCallList(uiTextFont + *s); glPopAttrib(); } void MenuDisplay(void) { int i, j; glClear(GL_COLOR_BUFFER_BIT); /*显示Level信息*/ glColor3f(1.0, 1.0, 1.0); glRasterPos3f(0.6, 0.1, 0.0);/*设置显示位置*/ PrintString("Level:"); glRasterPos3f(0.6, 0.0, 0.0); switch (iLevel) { case 0: PrintString("0"); break; case 1: PrintString("1"); break; case 2: PrintString("2"); break; case 3: PrintString("3"); break; case 4: PrintString("4"); break; default: PrintString("5"); } /*显示Help信息*/ glRasterPos3f(0.6, -0.25, 0.0); PrintString("Help:"); glRasterPos3f(0.6, -0.4, 0.0); PrintString("W----Roll"); glRasterPos3f(0.6, -0.5, 0.0); PrintString("S----Downwards"); glRasterPos3f(0.6, -0.6, 0.0); PrintString("A----Turn Left"); glRasterPos3f(0.6, -0.7, 0.0); PrintString("D----Turn Right"); glRasterPos3f(0.6, -0.8, 0.0); PrintString("ESC----EXIT"); /*显示预览方块信息*/ glRasterPos3f(0.6, 0.9, 0.0); PrintString("NextBlock:"); /*重置预览下一方块的四个坐标*/ for (i = 0; i<4; i++) { for (j = 0; j<2; j++) { afNextLoc[i][j] = afShapeNext[iNextBlock][i][j]; } } /*将预览方块涂色*/ for (i = 0; i < 4; i++) { glColor3f(1.0, 1.0, 0.0); glRectf(afNextLoc[i][0], afNextLoc[i][1], afNextLoc[i][0] + 0.1f, afNextLoc[i][1] + 0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f, 0.0f, 0.0f); glVertex2f(afNextLoc[i][0], afNextLoc[i][1]); glVertex2f(afNextLoc[i][0] + 0.1f, afNextLoc[i][1]); glVertex2f(afNextLoc[i][0] + 0.1f, afNextLoc[i][1] + 0.1f); glVertex2f(afNextLoc[i][0], afNextLoc[i][1] + 0.1f); glEnd(); glFlush(); } } void GotoXY(int x, int y) { COORD c; c.X = 2 * x; c.Y = y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), c); } /*选择键面操作*/ void Choose() { /*若是按下退出或开始游戏就退出循环*/ while (iStart != 0 && iStart != 1) { cButton = getch(); /*若是up和down就进行光标移动操作*/ if (cButton == 72 || cButton == 80) { if (stPoint.y == 13) { stPoint.y = 16; GotoXY(10, 13); printf(" "); GotoXY(10, 16); printf("——>"); GotoXY(12, 16); } else if (stPoint.y == 16) { stPoint.y = 13; GotoXY(10, 16); printf(" "); GotoXY(10, 13); printf("——>"); GotoXY(12, 13); } } /*按下esc键或enter退出游戏*/ if ((cButton == ENTER && stPoint.y == 16) || cButton == ESC) { iStart = 0; break; } /*开始游戏*/ if (cButton == ENTER && stPoint.y == 13) { iStart = 1; break; } } } void WelcomeScreen() { system("color 0F"); GotoXY(14, 1); printf("Welcome to play Tetris"); GotoXY(17, 7); printf("MAIN MENU"); GotoXY(15, 13); printf("***START GAME***"); GotoXY(15, 16); printf("***QUIT GAME***"); GotoXY(10, 13); printf("——>"); stPoint.x = 15; stPoint.y = 13; GotoXY(12, 13); Choose(); } void EndScreen() { system("cls");/*清屏函数*/ system("color 0F"); GotoXY(16, 3); printf("GAME OVER!!!\n"); GotoXY(15, 10); printf("YOU SCORE IS: %d\n", iScore * 100); GotoXY(15, 12); printf("YOU LEVEL IS: %d\n", iLevel); //GotoXY(15, 14); //printf("Quit choose ESC!\n"); #if 0 //重玩功能的实现,后续完善 cButton = getch(); if (cButton == 89) { iTimeS = 1000; iEndGame = 0; iLevel = 0; iOver = 0; iScore = 0; iLefRig = 0; InitBlock(); CreateBlocks(); glutPostRedisplay(); glutTimerFunc(iTimeS, Down, 1); } else { exit(1); } #endif } /*初始化字符绘制显示列表*/ void InitString(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); /*申请MAX_CHAR个连续的显示列表编号*/ uiTextFont = glGenLists(MAX_CHAR); /*把每个字符的绘制命令都装到对应的显示列表中*/ wglUseFontBitmaps(wglGetCurrentDC(), 0, MAX_CHAR, uiTextFont); } /*初始化方块矩阵,方块是一个上端开口的长方形*/ void InitBlock() { int i, j; for (i = 0; i < SIZE - 5; i++) for (j = 0; j < SIZE; j++) aiBlock[i][j] = 0; for (i = 0; i < SIZE - 5; i++) aiBlock[0][i] = 1; for (i = 0; i < SIZE; i++) { aiBlock[i][0] = 1; aiBlock[i][SIZE - 6] = 1; } for (i = 0; i<4; i++) for (j = 0; j<2; j++) afCurLoc[i][j] = afShape[iCurrentBlock][i][j]; } /*将图形做变换,采用顺时针旋转的规律*/ void Change() { int ret; /*用临时变量储存当前方块中四个小方块的坐标*/ GLfloat temp00 = afCurLoc[0][0]; GLfloat temp01 = afCurLoc[0][1]; GLfloat temp10 = afCurLoc[1][0]; GLfloat temp11 = afCurLoc[1][1]; GLfloat temp20 = afCurLoc[2][0]; GLfloat temp21 = afCurLoc[2][1]; GLfloat temp30 = afCurLoc[3][0]; GLfloat temp31 = afCurLoc[3][1]; int tempTurn = aiTurn[iCurrentBlock]; switch (iCurrentBlock) { case 0:/*长条*/ if (aiTurn[0] == 0)/*长条第1种形态*/ { afCurLoc[0][0] = temp10 - 0.1f; afCurLoc[0][1] = temp11; afCurLoc[2][0] = temp10 + 0.1f; afCurLoc[2][1] = temp11; afCurLoc[3][0] = temp10 + 0.2f; afCurLoc[3][1] = temp11; } else if (aiTurn[0] == 1)/*长条第2种形态*/ { afCurLoc[0][0] = temp10; afCurLoc[0][1] = temp11 + 0.1f; afCurLoc[2][0] = temp10; afCurLoc[2][1] = temp11 - 0.1f; afCurLoc[3][0] = temp10; afCurLoc[3][1] = temp11 - 0.2f; } /*使长条变到第2种形态后按'w'还可变成第1种形态*/ aiTurn[0] = (aiTurn[0] + 1) % 2; break; case 1:/*正方形*/ break; case 2:/*T字形*/ if (aiTurn[2] == 0) { afCurLoc[1][0] = temp20; afCurLoc[1][1] = temp21; afCurLoc[2][0] = temp30; afCurLoc[2][1] = temp31; afCurLoc[3][0] = temp20; afCurLoc[3][1] = temp21 - 0.1f; } else if (aiTurn[2] == 1) { afCurLoc[0][0] = temp10 - 0.1f; afCurLoc[0][1] = temp11; } else if (aiTurn[2] == 2) { afCurLoc[0][0] = temp10; afCurLoc[0][1] = temp11 + 0.1f; afCurLoc[1][0] = temp00; afCurLoc[1][1] = temp01; afCurLoc[2][0] = temp10; afCurLoc[2][1] = temp11; } else if (aiTurn[2] == 3) { afCurLoc[3][0] = temp20 + 0.1f; afCurLoc[3][1] = temp21; } aiTurn[2] = (aiTurn[2] + 1) % 4; break; case 3:/*Z字形*/ if (aiTurn[3] == 0) { afCurLoc[0][0] = temp10 + 0.1f; afCurLoc[0][1] = temp11 + 0.1f; afCurLoc[2][0] = temp10 + 0.1f; afCurLoc[2][1] = temp11; afCurLoc[3][0] = temp20; afCurLoc[3][1] = temp21; } else if (aiTurn[3] == 1) { afCurLoc[0][0] = temp10 - 0.1f; afCurLoc[0][1] = temp11; afCurLoc[2][0] = temp30; afCurLoc[2][1] = temp31; afCurLoc[3][0] = temp30 + 0.1f; afCurLoc[3][1] = temp31; } aiTurn[3] = (aiTurn[3] + 1) % 2; break; case 4:/*反Z字形*/ if (aiTurn[4] == 0) { afCurLoc[0][0] = temp00 - 0.1f; afCurLoc[0][1] = temp01 + 0.1f; afCurLoc[1][0] = temp00 - 0.1f; afCurLoc[1][1] = temp01; afCurLoc[2][0] = temp00; afCurLoc[2][1] = temp01; afCurLoc[3][0] = temp00; afCurLoc[3][1] = temp01 - 0.1f; } else if (aiTurn[4] == 1) { afCurLoc[0][0] = temp20; afCurLoc[0][1] = temp21; afCurLoc[1][0] = temp20 + 0.1f; afCurLoc[1][1] = temp21; afCurLoc[2][0] = temp10; afCurLoc[2][1] = temp11 - 0.1f; } aiTurn[4] = (aiTurn[4] + 1) % 2; break; case 5:/*L字形*/ if (aiTurn[5] == 0) { afCurLoc[0][0] = temp10; afCurLoc[0][1] = temp11; afCurLoc[1][0] = temp10 + 0.1f; afCurLoc[1][1] = temp11; afCurLoc[2][0] = temp10 + 0.2f; afCurLoc[2][1] = temp11; afCurLoc[3][0] = temp20; afCurLoc[3][1] = temp21; } else if (aiTurn[5] == 1) { afCurLoc[0][0] = temp00; afCurLoc[0][1] = temp01 + 0.1f; afCurLoc[1][0] = temp10; afCurLoc[1][1] = temp11 + 0.1f; afCurLoc[2][0] = temp10; afCurLoc[2][1] = temp11; afCurLoc[3][0] = temp10; afCurLoc[3][1] = temp11 - 0.1f; } else if (aiTurn[5] == 2) { afCurLoc[0][0] = temp20 + 0.1f; afCurLoc[0][1] = temp21; afCurLoc[1][0] = temp20 - 0.1f; afCurLoc[1][1] = temp21 - 0.1f; afCurLoc[2][0] = temp20; afCurLoc[2][1] = temp21 - 0.1f; afCurLoc[3][0] = temp20 + 0.1f; afCurLoc[3][1] = temp21 - 0.1f; } else if (aiTurn[5] == 3) { afCurLoc[0][0] = temp10; afCurLoc[0][1] = temp11 + 0.2f; afCurLoc[1][0] = temp10; afCurLoc[1][1] = temp11 + 0.1f; afCurLoc[2][0] = temp10; afCurLoc[2][1] = temp11; afCurLoc[3][0] = temp20; afCurLoc[3][1] = temp21; } aiTurn[5] = (aiTurn[5] + 1) % 4; break; case 6:/*反L字形*/ if (aiTurn[6] == 0) { afCurLoc[0][0] = temp20 - 0.1f; afCurLoc[0][1] = temp21 + 0.1f; afCurLoc[1][0] = temp20 - 0.1f; afCurLoc[1][1] = temp21; } else if (aiTurn[6] == 1) { afCurLoc[0][0] = temp00 + 0.1f; afCurLoc[0][1] = temp01 + 0.1f; afCurLoc[1][0] = temp30; afCurLoc[1][1] = temp31 + 0.2f; afCurLoc[2][0] = temp00 + 0.1f; afCurLoc[2][1] = temp01; afCurLoc[3][0] = temp20; afCurLoc[3][1] = temp21; } else if (aiTurn[6] == 2) { afCurLoc[0][0] = temp00 - 0.1f; afCurLoc[0][1] = temp01 - 0.1f; afCurLoc[1][0] = temp20; afCurLoc[1][1] = temp21; afCurLoc[2][0] = temp20 + 0.1f; afCurLoc[2][1] = temp21; afCurLoc[3][0] = temp30 + 0.1f; afCurLoc[3][1] = temp31; } else if (aiTurn[6] == 3) { afCurLoc[0][0] = temp20; afCurLoc[0][1] = temp21 + 0.1f; afCurLoc[1][0] = temp20; afCurLoc[1][1] = temp21; afCurLoc[2][0] = temp30 - 0.1f; afCurLoc[2][1] = temp31; afCurLoc[3][0] = temp30; afCurLoc[3][1] = temp31; } aiTurn[6] = (aiTurn[6] + 1) % 4; break; default: break; } /*如果旋转非法(即旋转时碰到墙壁),则恢复原状态*/ ret = CheckConflict(iLefRig); if (ret == 1) { afCurLoc[0][0] = temp00; afCurLoc[0][1] = temp01; afCurLoc[1][0] = temp10; afCurLoc[1][1] = temp11; afCurLoc[2][0] = temp20; afCurLoc[2][1] = temp21; afCurLoc[3][0] = temp30; afCurLoc[3][1] = temp31; aiTurn[iCurrentBlock] = tempTurn; } } /* 消除满格的一行,在每次over被修改为1的时候都要检查一遍 算法思想是从第0行开始依次判断,如果empty为1则将下面的向上, 并不是判断一次就移动所有的,而是只移动最近的,将空出来的 那一行的empty标记为1 */ /* empty[i]=1表示第i行空 empty[i]=0表示第i行满 empty[i]=-1表示第i行部分空 */ void Delete(int *empty) { int i, j; int pos; while (1) /*将上面满行移动到非空行之下*/ { i = 1; /*若第i行的状态为“部分空”,则i++;否则状态为满行,需要将上面的行移下来填充*/ while (i < SIZE && empty[i] == 0) i++; if (i >= SIZE) break; j = i + 1; /*i行为满行*/ while (j < SIZE && empty[j] == -1) j++; if (j >= SIZE) break; else if(empty[j] != -1) { for (pos = 1; pos < 15; pos++) aiBlock[i][pos] = aiBlock[j][pos]; empty[i] = empty[j];/*将第j行与第i行的状态交换*/ empty[j] = -1; /*j行变为空行*/ } } /*将空行和满行的中的所有方块都置为0*/ for (i = 1; i < SIZE; i++) { if (empty[i] != 0)/*-1为空行,1为满行*/ { for (j = 1; j < 14; j++) aiBlock[i][j] = 0; } } } void CheckDelete() { int i, j; int empty[SIZE]; int is_needed = 0; int count; for (i = 1; i<SIZE; i++) empty[i] = -1;/*初始均为空行,置为-1*/ for (i = 0; i<4; i++) { /*将坐标(x,y)转化为边框中对应的小格数*/ double x = (afCurLoc[i][0] + 1) * 10 + 0.5; double y = (afCurLoc[i][1] + 1) * 10 + 0.5; aiBlock[(int)y][(int)x] = 1; } for (i = 1; i< SIZE; i++) { count = 0; for (j = 1; j<14; j++) if (aiBlock[i][j] == 1) count++; if (count == 13) { empty[i] = 1; /*满行,置为1*/ iScore++; /*此处计分*/ iTimeS -= 50; /*下落速度加快*/ is_needed = 1; /*满行,需要消除,置为1*/ } else if (count > 0 && count < 13) { empty[i] = 0;/*非满行,也非空行,称作“部分空”,置为0*/ } } if (is_needed == 1)/*如果有满行则去删除*/ Delete(empty); } int CheckConflict(int iLefRig) { int i, tmpx; for (i = 0; i<4; i++) { double x = (afCurLoc[i][0] + 1) * 10; double y = (afCurLoc[i][1] + 1) * 10 + 0.5; x = x>0 ? (x + 0.5) : (x - 0.5); if (iLefRig == 1) { tmpx = (int)x; if (tmpx > 13 || tmpx < 1) break; } if (aiBlock[(int)y][(int)x] == 1) /*判断是否发生冲突*/ { break; } } if (i < 4) return 1; return 0; } void Key(unsigned char k, int x, int y) { int i, ret; if (iOver == 0) { switch (k) { case UP:/*若按'w',方块变换*/ Change(); break; case DOWN:/*若按's',方块下移*/ for (i = 0; i < 4; i++) { afCurLoc[i][1] -= 0.1f; } ret = CheckConflict(1); if (ret == 1)/*发生冲突,则将修改复原*/ { for (i = 0; i < 4; i++) afCurLoc[i][1] += 0.1f; iOver = 1;/*并且可以生成下一个方块了*/ } break; case RIGHT:/*若按'd',方块右移*/ for (i = 0; i < 4; i++) { afCurLoc[i][0] += 0.1f; } ret = CheckConflict(1); if (ret == 1)/*发生冲突,则将修改复原*/ { for (i = 0; i<4; i++) afCurLoc[i][0] -= 0.1f; } break; case LEFT:/*若按'a',方块左移*/ for (i = 0; i < 4; i++) { afCurLoc[i][0] -= 0.1f; } ret = CheckConflict(1); if (ret == 1)/*发生冲突,则将修改复原*/ { for (i = 0; i<4; i++) afCurLoc[i][0] += 0.1f; } break; case ESC:/*若按Esc,游戏退出*/ exit(1); break; } } if (iOver == 1) CheckDelete(); /*调用这个函数可以重新绘图,每次相应消息之后,所有全部重绘*/ glutPostRedisplay(); } /*让方块定时下降*/ void Down(int id) { int i, ret; if (iOver == 0) { /*将每个方块纵坐标下移0.1个单位长度*/ for (i = 0; i<4; i++) { afCurLoc[i][1] -= 0.1f; } ret = CheckConflict(iLefRig); if (ret == 1)/*发生冲突,则将修改复原*/ { for (i = 0; i<4; i++) afCurLoc[i][1] += 0.1f; /*若方块生成初始位置超出屏幕,则游戏结束*/ if (afCurLoc[0][1] >= afShape[iCurrentBlock][0][1]) { iEndGame = 1; EndScreen(); return; } iOver = 1;/*并且可以生成下一个方块了*/ } /*根据下落速度提升等级*/ if (iTimeS >= 1000) iLevel = 0; else if (iTimeS >= 900) iLevel = 1; else if (iTimeS >= 700) iLevel = 2; else if (iTimeS >= 500) iLevel = 3; else if (iTimeS >= 300) iLevel = 4; else iLevel = 5; } if (iOver == 1) CheckDelete(); glutPostRedisplay(); glutTimerFunc(iTimeS, Down, 1); } /*画图函数,用aiBlock数组绘图*/ void BlockDisplay() { int i, j; static int s = 0; glClear(GL_COLOR_BUFFER_BIT); MenuDisplay(); for (i = 0; i<20; i++)/*将游戏区域边框涂为灰色*/ { for (j = 0; j<15; j++) { if (aiBlock[i][j] == 1) { glColor3f(0.7f, 0.7f, 0.7f); glRectf(j / 10.0f - 1.0f, i / 10.0f - 1.0f, j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f + 0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f, 0.0f, 0.0f); glVertex2f(j / 10.0f - 1.0f, i / 10.0f - 1.0f); glVertex2f(j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f); glVertex2f(j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f + 0.1f); glVertex2f(j / 10.0f - 1.0f, i / 10.0f - 1.0f + 0.1f); glEnd(); glFlush(); } s++; } } for (i = 1; i<20; i++)/*将已落到底部的方块涂为白色*/ { for (j = 1; j<14; j++) { if (aiBlock[i][j] == 1) { glColor3f(1.0f, 1.0f, 1.0f); glRectf(j / 10.0f - 1.0f, i / 10.0f - 1.0f, j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f + 0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f, 0.0f, 0.0f); glVertex2f(j / 10.0f - 1.0f, i / 10.0f - 1.0f); glVertex2f(j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f); glVertex2f(j / 10.0f - 1.0f + 0.1f, i / 10.0f - 1.0f + 0.1f); glVertex2f(j / 10.0f - 1.0f, i / 10.0f - 1.0f + 0.1f); glEnd(); glFlush(); } s++; } } if (iOver == 0) { for (i = 0; i < 4; i++) { /*使方块在下落中可在三种颜色中变化*/ if (s % 3 == 0) glColor3f(1.0, 0.0, 0.0); else if (s % 3 == 1) glColor3f(0.0, 1.0, 0.0); else if (s % 3 == 2) glColor3f(0.0, 0.0, 1.0); glRectf(afCurLoc[i][0], afCurLoc[i][1], afCurLoc[i][0] + 0.1f, afCurLoc[i][1] + 0.1f); glLineWidth(2.0f); glBegin(GL_LINE_LOOP); glColor3f(0.0f, 0.0f, 0.0f); glVertex2f(afCurLoc[i][0], afCurLoc[i][1]); glVertex2f(afCurLoc[i][0] + 0.1f, afCurLoc[i][1]); glVertex2f(afCurLoc[i][0] + 0.1f, afCurLoc[i][1] + 0.1f); glVertex2f(afCurLoc[i][0], afCurLoc[i][1] + 0.1f); glEnd(); glFlush(); } } s++; glutSwapBuffers(); } /*随机生成方块,原理即生成一个7以内的随机数, 对应的二维数组即为下一个产生的方块*/ void CreateBlocks(void) { int i, j; /*若游戏未结束,则生成下一方块*/ if (iEndGame == 0) { //srand(time(NULL)); BlockDisplay(); /*若方块落到底部,则将原预览方块信息赋给当前下落方块, 并随机生成预览方块*/ if (iOver) { srand(time(NULL)); iCurrentBlock = iNextBlock; iNextBlock = rand() % 7; /*每次创建一个新的方块后要将变形的记录清空*/ for (i = 0; i < 7; i++) aiTurn[i] = 0; for (i = 0; i < 4; i++) for (j = 0; j < 2; j++) { afCurLoc[i][j] = afShape[iCurrentBlock][i][j]; } iOver = 0; glutPostRedisplay(); } } } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); glutInitWindowPosition(400, 0);/*设置窗口在屏幕中的位置*/ glutInitWindowSize(750, 720);/*设置窗口的大小*/ WelcomeScreen(); if (iStart) { InitBlock();/*图形界面绘制*/ glutCreateWindow("俄罗斯方块");/*创建窗口。参数作为窗口的标题*/ InitString();/*显示帮助*/ glutDisplayFunc(&CreateBlocks);/*当需要进行画图时,调用该函数*/ glutTimerFunc(iTimeS, Down, 1);/*定时下落方块*/ glutKeyboardFunc(Key); glClearColor(0.0f, 0.0f, 0.0f, 0.0f);/*用黑色清除屏幕*/ glutMainLoop();/*进行一个消息循环*/ } return 0; }