#include //标准输入输出 #include //控制控制台 #include //接收键盘信号 #include //调用随机数函数 #define FrameX 13 // 游戏窗口左上角X坐标 #define FrameY 3 //游戏窗口左上角Y坐标 #define Frame_gao 20 //游戏窗口高度 #define Frame_kuan 18 //游戏窗口宽度 int i, j, temp, temp1, temp2; //定义全局变量, temp表示存储方块变量的值 int a[80][80] = {0}; //0表示无方块,1表示有方块, 2为边界 int b[4]; //四个方块,值为0,1 struct fangkuai { int x, y; //横纵坐标值 int flag; //方块类型序号 int next; //下一个方块序号 int speed; // 方块速度 int number; //方块个数 int score; //分数 int level; //游戏等级 }; HANDLE hOut; //控制台控制 /********函数声明**********/ void gotoxy(int x, int y); //光标移动到指定位置 int color(int c); //控制台文字颜色 void DrawGameframe(); //绘制游戏边界 void Flag(struct fangkuai *); //产生随机数 void Makefangkuai(struct fangkuai *); //制作方块 void printfangkuai(struct fangkuai *); //打印~ void cleanfangkuai(struct fangkuai *); //清除~ int ifMove(struct fangkuai *); //判断是否可移动 void Del_fullline(struct fangkuai *); //判断是否满行,并删除满行方块 void Gamebegin(); //游戏开始 void welcome(); //欢迎菜单 void explation(); //规则说明 void Replay(struct fangkuai *); //重新游戏 void title(); //界面上方标题 void close(); //关闭游戏 /*****控制文字颜色*******/ int color(int c){ SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c); //只在windows上改变文字颜色 return 0; } //0~15,共16种颜色 /*用法: coler(数字) printf */ /*******文字显示位置********/ void gotoxy(int x, int y) { COORD pos; pos.X = x; pos.Y = y; SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),pos); } /* 用法: gotoxy(30,10) 横向空30个单位,纵向空10个单位 printf */ /*****设置开始界面标题*****/ void title() { color(15); gotoxy(30,3); printf(" 俄 罗 斯 方 块"); color(11); gotoxy(17,5); printf("■"); gotoxy(17,6); printf("■■"); gotoxy(17,7); printf("■"); color(10); gotoxy(25,5); printf("■■"); gotoxy(25,6); printf("■■"); color(13); gotoxy(33,6); printf("■■■■"); color(4); gotoxy(45,5); printf("■■"); gotoxy(45,6); printf(" ■"); gotoxy(45,7); printf(" ■"); color(12); gotoxy(53,5); printf("■■"); gotoxy(53,6); printf(" ■■"); } /*****设置菜单选项*****/ void welcome(){ int i = 1, j = 1; int n; color(14); for(i = 9; i <= 20; i++){ for(j = 15; j <= 60; j++){ gotoxy(j, i); if(i == 9 || i == 20){ printf("="); } else if(j == 15 || j == 59){ printf("||"); } } } color(12); gotoxy(25,12); printf("1.开始游戏"); gotoxy(40,12); printf("2.说明和规则"); gotoxy(33,17); printf("3.退出游戏\n"); gotoxy(31,19); printf("本游戏纯属内测"); gotoxy(28,22); color(3); printf("请选择[1 2 3]:{ }\b\b"); color(14); scanf("%d", &n); switch(n) { case 1: { system("cls"); //清屏 DrawGameframe(); Gamebegin(); break; } case 2: explation(); break; case 3: close(); break; } } /*****游戏窗口界面*****/ void DrawGameframe() { gotoxy((FrameX+Frame_kuan-7), FrameY-2); color(11); printf("俄罗斯方块"); color(12); gotoxy(FrameX,FrameY); printf("┎"); gotoxy(FrameX + 2*Frame_kuan-2,FrameY); printf("┒"); gotoxy(FrameX,FrameY + Frame_gao); printf("┖"); gotoxy(FrameX+ 2*Frame_kuan-2,FrameY + Frame_gao); printf("┚"); a[FrameX+ 2*Frame_kuan-2][FrameY + Frame_gao] = 2; /****上横框*****/ for(i = 2; i < 2 * Frame_kuan-2; i += 2){ gotoxy(FrameX + i, FrameY); printf("━"); } /*****下横框*****/ for(i = 2; i < 2 * Frame_kuan-2; i += 2){ gotoxy(FrameX + i, FrameY + Frame_gao); printf("━"); a[FrameX + i][FrameY + Frame_gao] = 2; } /****竖框****/ for(i = 1; i < Frame_gao; i++){ //左 gotoxy(FrameX, FrameY+i); printf("┃"); a[FrameX][FrameY + i] = 2; } for(i = 1; i < Frame_gao; i++){ gotoxy(FrameX + 2 * Frame_kuan-2, FrameY+i); printf("┃"); a[FrameX + 2 * Frame_kuan-2][FrameY+i] = 2; } /****提示****/ color(2); gotoxy(FrameX + 2* Frame_kuan + 3,FrameY + 7); printf("**********"); gotoxy(FrameX + 2* Frame_kuan + 3,FrameY + 13); printf("**********"); color(3); gotoxy(FrameX + 2* Frame_kuan + 3,FrameY + 6); printf("下一个方块:"); color(14); gotoxy(FrameX + 2* Frame_kuan + 3,FrameY + 17); printf("空格:暂停游戏"); gotoxy(FrameX + 2* Frame_kuan + 3,FrameY + 19); printf("ESC:退出游戏"); } /****制作方块*****/ void Makefangkuai(struct fangkuai *tetris) { a[tetris->x][tetris->y] = b[0]; switch(tetris->flag) { case 1: //田字方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x+2][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 2: //直线方块:---- { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x+2][tetris->y]=b[2]; a[tetris->x+4][tetris->y]=b[3]; break; } case 3: //直线方块: | { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y-2]=b[2]; a[tetris->x][tetris->y+1]=b[3]; break; } case 4: //T字方块 { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x+2][tetris->y]=b[2]; a[tetris->x][tetris->y+1]=b[3]; break; } case 5: //T字顺时针转90度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y+1]=b[2]; a[tetris->x-2][tetris->y]=b[3]; break; } case 6: //T字顺时针转180度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x-2][tetris->y]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 7: //T字顺时针转270度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y+1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 8: //Z字方块 { a[tetris->x][tetris->y+1]=b[1]; a[tetris->x-2][tetris->y]=b[2]; a[tetris->x+2][tetris->y+1]=b[3]; break; } case 9: //Z字顺时针转90度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x-2][tetris->y]=b[2]; a[tetris->x-2][tetris->y+1]=b[3]; break; } case 10: //Z字顺时针转180度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x-2][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 11: //Z字顺时针转270度方块 { a[tetris->x][tetris->y+1]=b[1]; a[tetris->x+2][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 12: //7字方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y+1]=b[2]; a[tetris->x-2][tetris->y-1]=b[3]; break; } case 13: //7字顺时针转90度方块 { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x-2][tetris->y+1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 14: //7字顺时针转180度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y+1]=b[2]; a[tetris->x+2][tetris->y+1]=b[3]; break; } case 15: //7字顺时针转270度方块 { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x+2][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 16: //倒7字方块 { a[tetris->x][tetris->y+1]=b[1]; a[tetris->x][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y-1]=b[3]; break; } case 17: //倒7字顺指针转90度方块 { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x-2][tetris->y-1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } case 18: //倒7字顺时针转180度方块 { a[tetris->x][tetris->y-1]=b[1]; a[tetris->x][tetris->y+1]=b[2]; a[tetris->x-2][tetris->y+1]=b[3]; break; } case 19: //倒7字顺时针转270度方块 { a[tetris->x-2][tetris->y]=b[1]; a[tetris->x+2][tetris->y+1]=b[2]; a[tetris->x+2][tetris->y]=b[3]; break; } } } /****打印方块*****/ void Printfangkuai(struct fangkuai *tetris) { for(i = 0; i < 4; i++) { b[i] = 1; } Makefangkuai(tetris); for(i = tetris->x-2; i <= tetris->x+4; i += 2){ for(j = tetris->y-2; j <= tetris->y+1; j++){ if(a[i][j] == 1 && j > FrameY){ gotoxy(i, j); printf("■"); } } } /*****打印信息******/ gotoxy(FrameX + 2 * Frame_kuan+3,FrameY + 1); color(4); printf("等级: "); color(12); printf("%d", tetris->level); gotoxy(FrameX + 2 * Frame_kuan+3,FrameY + 3); color(4); printf("分数: "); color(12); printf("%d", tetris->score); gotoxy(FrameX + 2 * Frame_kuan+3,FrameY + 5); color(4); printf("速度: "); color(12); printf("%dms", tetris->speed); } /*****判断是否可移动*****/ int ifMove(struct fangkuai *tetris) { if(a[tetris->x][tetris->y] != 0){ //中心方块处不为空 return 0; } else { if(//当为田字方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动 ( tetris->flag==1 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || //或为直线方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动 ( tetris->flag==2 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 && a[tetris->x+4][tetris->y]==0 ) ) || ( tetris->flag==3 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y-2]==0 && a[tetris->x][tetris->y+1]==0 ) ) || ( tetris->flag==4 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 && a[tetris->x][tetris->y+1]==0 ) ) || ( tetris->flag==5 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y]==0 ) ) || ( tetris->flag==6 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==7 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==8 && ( a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) || ( tetris->flag==9 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) || ( tetris->flag==10 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==11 && ( a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==12 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y-1]==0 ) ) || ( tetris->flag==13 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==14 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) || ( tetris->flag==15 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==16 && ( a[tetris->x][tetris->y+1]==0 && a[tetris->x][tetris->y-1]==0 && a[tetris->x+2][tetris->y-1]==0 ) ) || ( tetris->flag==17 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) || ( tetris->flag==18 && ( a[tetris->x][tetris->y-1]==0 && a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) || ( tetris->flag==19 && ( a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ) { return 1; } } return 0; } /*****清除方块轨迹******/ void Cleanfangkuai(struct fangkuai *tetris) { for(i = 0; i < 4; i++){ b[i] = 0; } Makefangkuai(tetris); for(i = tetris->x-2; i <= tetris->x+4; i += 2){ for(j = tetris->y-2; j <= tetris->y + 1; j++){ if(a[i][j] == 0 && j > FrameY){ gotoxy(i, j); printf(" "); //将上一个方块的轨迹以空格代替 } } } } /******判断满行并删除******/ void Del_fullline(struct fangkuai *tetris) { int k, del_rows = 0; for(j = FrameY+Frame_gao-1; j >= FrameY+1; j--){ k=0; for(i = FrameX+2; i < FrameX + 2* Frame_kuan - 2; i += 2){ //从左下角开始向右上方遍历 if(a[i][j] == 1){ k++; if(k == Frame_kuan - 2) //k代表i——横坐标 { for(k = FrameX + 2; k < FrameX + 2 * Frame_kuan - 2; k += 2) { a[k][j] = 0; gotoxy(k, j); printf(" "); //删除整行 } for(k = j-1; k > FrameY; k--) //k代表j——纵坐标 { for(i = FrameX + 2; i < FrameX + 2 * Frame_kuan-2; i += 2) { if(a[i][k] == 1) { a[i][k] == 0; gotoxy(i,k); printf(" "); a[i][k+1] == 1; gotoxy(i, k+1); printf("■"); } } } j++; del_rows++; //记录删除行数 } } } } tetris->score += 100*del_rows; //得分 if(del_rows > 0 && (tetris->score % 1000 == 0 || (tetris->score / 1000) > (tetris->level-1))) { tetris->speed -= 20; tetris->level++; } } /*****随机产生方块*****/ void Flag(struct fangkuai *tetris) { tetris->number++; srand(time(NULL)); //初始化随机数 if(tetris->number == 1) { tetris->flag == rand()%19+1; //rand产生随机数,除取余,结果为0~18 } tetris->next = rand()%19+1; } /*******开始游戏********/ void Gamebegin() { int n; struct fangkuai t, *tetris = &t; //定义变量 char ch; tetris->number = 0; //初始方块数为0 tetris->speed = 300; //初始化速度 tetris->score = 0; //初始得分 tetris->level = 1; //初始等级 while(1) { Flag(tetris); temp = tetris->flag; //temp将下一个方块输入到游戏中 tetris->x = FrameX + 2 * Frame_kuan + 6; tetris->y = FrameY +10; tetris->flag = tetris->next; Printfangkuai(tetris); tetris->x = FrameX + Frame_kuan; tetris->y = FrameY -1; tetris->flag = temp; //按键操作 while(1) //控制方块变化,直至不再下落 { label:Printfangkuai(tetris); //打印方块 Sleep(tetris->speed); //延缓时间 Cleanfangkuai(tetris); //清除痕迹 temp1 = tetris->x; //标定中心方块横坐标的值 temp2 = tetris->flag; //记住当前俄罗斯方块的序号 if(kbhit()) //判断是否有键盘输入(kbhit) { ch = getch(); //用ch接收 if((ch == 75) || (ch == 'a' || ch == 'A')) { tetris->x-=2; //方向键左或A,则向左移动,中心横坐标减2 } if((ch == 77) || (ch == 'd' || ch == 'D')) { tetris->x+=2; //方向键右或D,则向右移动,中心横坐标加2 } if((ch == 0x28) || (ch == 's' || ch == 'S')) //下键或S,则向下加速 { if(ifMove(tetris) != 0) { tetris->y+=2; } if(ifMove(tetris) == 0) { tetris->y = FrameY + Frame_gao - 2; } } if((ch == 72) || (ch == 'w' || ch == 'W')) //按上键和W改变方块形状 { if( tetris->flag>=2 && tetris->flag<=3 ) { tetris->flag++; tetris->flag%=2; tetris->flag+=2; } if( tetris->flag>=4 && tetris->flag<=7 ) { tetris->flag++; tetris->flag%=4; tetris->flag+=4; } if( tetris->flag>=8 && tetris->flag<=11 ) { tetris->flag++; tetris->flag%=4; tetris->flag+=8; } if( tetris->flag>=12 && tetris->flag<=15 ) { tetris->flag++; tetris->flag%=4; tetris->flag+=12; } if( tetris->flag>=16 && tetris->flag<=19 ) { tetris->flag++; tetris->flag%=4; tetris->flag+=16; } } if(ch == 32){ //空格,暂停 Printfangkuai(tetris); while(1) { if(kbhit()) { ch == getch(); //再按,继续游戏 if(ch == 32) { goto label; } } } } if(ch == 27) //按ESC退出至菜单界面 { system("cls"); memset(a,0,6400*sizeof(int)); //初始化BOX数据 welcome(); } if(ifMove(tetris) == 0) //如果不可动,上述操作无效 { tetris->x = temp1; tetris->flag = temp2; } else { goto label; } } tetris->y++; //若无操作指令,则方块自由下落 if(ifMove(tetris) == 0) //若方块不可移动,则方块放置于此 { tetris->y--; Printfangkuai(tetris); Del_fullline(tetris); break; } } for(i = tetris->y; i < tetris->y+1; i++) //方块触及顶部,游戏结束 { if(i == FrameY) { system("cls"); gotoxy(29,7); printf(" \n"); color(12); printf("\t\t\t■■■■ ■ ■ ■■■\n"); printf("\t\t\t■ ■■ ■ ■ ■\n"); printf("\t\t\t■■■■ ■ ■ ■ ■ ■\n"); printf("\t\t\t■ ■ ■■ ■ ■\n"); printf("\t\t\t■■■■ ■ ■ ■■■\n"); gotoxy(17,18); color(14); printf("我还要玩------1"); gotoxy(44,18); printf("我不玩了------2\n"); int n; gotoxy(32,20); printf("选择【1/2】:"); color(11); scanf("%d", &n); switch(n) { case 1: { system("cls"); Replay(tetris); //重新开始游戏 break; } case 2: exit(0); break; } } } tetris->flag = tetris->next; //清除右边窗口的下一个方块 tetris->x = FrameX + 2 * Frame_kuan +6; tetris->y = FrameY + 10; Cleanfangkuai(tetris); } } /******重新开始******/ void Replay(struct fangkuai *tetris) { system("cls"); memset(a,0,6400*sizeof(int)); //memset——初始化数组(数组名,数据,数组个数*长度) DrawGameframe(); Gamebegin(); } /*******规则说明*******/ void explation() { int i, j = 1; system("cls"); color(13); gotoxy(32,3); printf("按键说明"); color(2); for(i == 6; i <= 16; i++) //y轴坐标值 { for(j = 15; j <= 60; j++) { gotoxy(j,i); if(i == 6 || i == 16) { printf("="); } else if(j == 15 || j == 59) { printf("||"); } } } color(3); gotoxy(18,7); printf("tip1:玩家可以通过A、D或左右方向键控制方向"); color(10); gotoxy(18,9); printf("tip2:通过W或上方向键使方块逆时针旋转"); color(14); gotoxy(18,11); printf("tip3:通过S或下方向键加速方块下落"); color(11); gotoxy(18,13); printf("tip4:按空格暂停游戏,再按空格继续"); color(4); gotoxy(18,15); printf("tip5:按ESC退出游戏"); getch(); //按任意键返回主菜单 system("cls"); main(); } /****退出游戏****/ void close() { exit(0); } int main(){ title(); welcome(); }