游戏俄罗斯方块(c语言)
2021/9/28 23:13:03
本文主要是介绍游戏俄罗斯方块(c语言),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
游戏俄罗斯方块(c语言)
- 一、项目背景
- 二、设计目的
- 三、项目功能需求
- 1、游戏方块控制
- 2、游戏显示更新
- 3、游戏速度等级更新
- 4、游戏帮助
- 四、系统的功能结构图
- 五、总体设计
- 1、界面显示模块
- 2、开始与结束模块
- 3、移动变换模块
- 4、判断冲突模块
- 5、满行消除模块
- 六、详细设计
- 1、主函数
- 2、界面显示模块
- 3、开始与结束界面模块
- 4、移动变换模块
- 5、判断冲突模块
- 6、满行消除模块
- 七、代码
一、项目背景
俄罗斯方块(Terris, 俄文:Тетрис)是一款电视游戏机和掌上游戏机游戏。俄罗斯方块的基本规则是移动、旋转和摆放游戏自动输出的各种方块,使之排列成完整的一行或多行并且消除得分。
二、设计目的
- 如何用OpenGL编写画图程序
- 如何用数组储存信息
- 如何实现菜单的显示、选择和响应等功能
- 如何实现图形的移动,变换等功能
三、项目功能需求
1、游戏方块控制
- 通过各种条件的判断,实现对游戏方块的左移、右移、快速下落、自由下落、旋转功能,以及行满消除的功能
2、游戏显示更新
-
当游戏方块左右移动、下落、旋转时,要先清除先前的游戏方块,用新坐标重绘游戏方块
-
当消除满行时,要重绘游戏底板的当前状态
3、游戏速度等级更新
- 当游戏玩家进行游戏过程中,需要按照一定的游戏规则给游戏玩家计算游戏分数
4、游戏帮助
- 游戏玩家进入游戏后,将有对本游戏如何操作的友好提示。
四、系统的功能结构图
五、总体设计
功能模块介绍
1、界面显示模块
- 创建游戏主窗口并将游戏帮助显示在游戏界面上。
2、开始与结束模块
- 在游戏开始前创建一个欢迎进入游戏的提示窗口,玩家可选择进入游戏或退出游戏
3、移动变换模块
- 通过对按键的判断,实现方块的移动、变换等功能
4、判断冲突模块
- 该模块可判断移动是否合法,防止出现方块重叠、越界的情况。
5、满行消除模块
- 该模块是几个功能的集合,包括对满行方块的消除、对分数的更新以及对下落速度、等级的变化处理。
六、详细设计
1、主函数
首先初始化OpenGL描画库资源,然后进入的是游戏 欢迎界面,由玩家选择是否进入游戏,或者直接退出。
处理流程如图
2、界面显示模块
功能设计
- 实现对游戏窗口的创建,方块下落的循环操作**。**
- 还可实现字符的显示,将游戏帮助显示在屏幕上。
3、开始与结束界面模块
功能设计
- 在游戏开始前,创建一个游戏欢迎窗口,用户可通过自主移动光标选择是否开始。
- 在游戏结束时创建一个游戏结束窗口,在该结束界面显示分数,等级信息。
4、移动变换模块
功能设计
- 通过按键来实现方块的移动和旋转变形。
- 当某一(些)行达到满行时,将该(这些)行的方块全部消除,并将上方非满方块的行下移**。**
5、判断冲突模块
功能设计
- 检查方块移动或变形后是否超出游戏边界。
- 如果移动或变形后超出边界,则本次变形操作无效,保持原来的形状和位置**。**
6、满行消除模块
功能设计
- 当方块下落到底部时,会检查是否出现了满行。
- 若方块满行,则消除该行方块,得分增加**。**
七、代码
#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; }
这篇关于游戏俄罗斯方块(c语言)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2025-01-14深入理解 ECMAScript 2024 新特性:Promise.withResolvers
- 2025-01-13SRM vs SCM:企业管理中的差异战略与实践
- 2025-01-12深入理解 ECMAScript 2024 新特性:Map.groupBy() 分组操作
- 2025-01-11国产医疗级心电ECG采集处理模块
- 2025-01-10Rakuten 乐天积分系统从 Cassandra 到 TiDB 的选型与实战
- 2025-01-09CMS内容管理系统是什么?如何选择适合你的平台?
- 2025-01-08CCPM如何缩短项目周期并降低风险?
- 2025-01-08Omnivore 替代品 Readeck 安装与使用教程
- 2025-01-07Cursor 收费太贵?3分钟教你接入超低价 DeepSeek-V3,代码质量逼近 Claude 3.5
- 2025-01-06PingCAP 连续两年入选 Gartner 云数据库管理系统魔力象限“荣誉提及”