#include <graphics.h> #include <stdio.h> #include <dos.h> #include <conio.h> #include <time.h> #include <math.h> #include <stdlib.h> /*定义左上角点在屏幕上的位置*/ #define MAPXOFT 9 #define MAPYOFT 5 /*定义下一个方块显示的位置*/ #define MAPXOFT1 13 #define MAPYOFT1 -2 #define LEFT 0x4b00 #define RIGHT 0x4d00 #define DOWN 0x5000 /*此键为加速键*/ #define UP 0x4800 /*此键为变形键*/ #define ESC 0x011b /*此键为退出键*/ #define ENTER 0x1c0d #define TIMER 0x1c /* 时钟中断的中断号 */ /* 中断处理函数在C和C++中的表示略有不同。 如果定义了_cplusplus则表示在C++环境下,否则是在C环境下。 */ #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif int TimerCounter=0; /* 计时变量,每秒钟增加18。 */ /* 指向原来时钟中断处理过程入口的中断处理函数指针(句柄) */ void interrupt ( *oldhandler)(__CPPARGS); /* 新的时钟中断处理函数 */ void interrupt newhandler(__CPPARGS) { /* increase the global counter */ TimerCounter++; /* call the old routine */ oldhandler(); } /* 设置新的时钟中断处理过程 */ void SetTimer(void interrupt (*IntProc)(__CPPARGS)) { oldhandler=getvect(TIMER); disable(); /* 设置新的时钟中断处理过程时,禁止所有中断 */ setvect(TIMER,IntProc); enable(); /* 开启中断 */ } /* 恢复原有的时钟中断处理过程 */ void KillTimer() { disable(); setvect(TIMER,oldhandler); enable(); } struct shape { int xy[8],next; }; struct shape shapes[19]= { /*x1,y1,x2,y2,x3,y3,x4,y4 指四个小方块的相对坐标,next指此方块变形后应变为哪个小方块 { x1,y1,x2,y2,x3,y3,x4,y4,next}*/ { 0,-2, 0,-1, 0, 0, 1, 0, 1}, {-1, 0, 0, 0, 1,-1, 1, 0, 2}, { 0,-2, 1,-2, 1,-1, 1, 0, 3}, {-1,-1,-1, 0, 0,-1, 1,-1, 0}, { 0,-2, 0,-1, 0, 0, 1,-2, 5}, {-1,-1, 0,-1, 1,-1, 1, 0, 6}, { 0, 0, 1,-2, 1,-1, 1, 0, 7}, {-1,-1,-1, 0, 0, 0, 1, 0, 4}, {-1, 0, 0,-1, 0, 0, 1, 0, 9}, { 0,-2, 0,-1, 0, 0, 1,-1,10}, {-1,-1, 0,-1, 1,-1, 0, 0,11}, { 0,-1, 1,-2, 1,-1, 1, 0, 8}, {-1, 0, 0,-1, 0, 0, 1,-1,13}, { 0,-2, 0,-1, 1,-1, 1, 0,12}, {-1,-1, 0,-1, 0, 0, 1, 0,15}, { 0,-1, 0, 0, 1,-2, 1,-1,14}, { 0,-3, 0,-2, 0,-1, 0, 0,17}, {-1, 0, 0, 0, 1, 0, 2, 0,16}, { 0,-1, 0, 0, 1,-1, 1, 0,18} }; int board[10][20]={0};/*定义游戏板初始化为0*/ char sp[]="0",le[]="0",sc[]="00000"; int speed,speed0,level,score; int sign,flag; int style,style1; /*style为当前方块的种类,style1为即将输出的方块的种类*/ void draw_block(int x,int y,int style,int way); void draw_little_block(int x,int y); void init(); void initialize(); void speed_change(void); void score_change(int); void kill_line(int y); void fill_board(int x,int y, int style); int change(int *i,int *j,int key); void renovate(void); void ajustment(void); void level_change(void); main() { int i,j,key,x0=5,y0=1; randomize(); while(!flag) /*flag为0表示重新开始游戏*/ { level=score=speed=0; strcpy(le,"0"); strcpy(sp,"0"); strcpy(sc,"00000"); for(i=0;i<10;i++) for(j=0;j<20;j++) board[i][j]=0; /*初始化一些变量为0*/ initialize(); /*初始化进入图形模式*/ init(); /*初始化游戏板记分器等*/ SetTimer(newhandler); /* 修改时钟中断 */ ajustment(); /*开始游戏前调整速度和高度*/ if(level>0) level_change(); /*根据高度随机确定方块是否存在*/ style=random(19); /*随机确定方块种类*/ while(1) { i=x0,j=y0; style1=random(19); /*随机确定即将出现的方块种类*/ setcolor(WHITE); sign=1; draw_block(MAPXOFT1,MAPYOFT1,style1,1); /*画出即将出现的方块*/ for(j=y0;j<=20;j++) /*使方块下降*/ { if(!check_block(i,j,style)) break; draw_block(i,j,style,1); while(1) { if(speed0==0) /*未按下加速键时的处理*/ { if (TimerCounter>18/(speed+1)) { /* 恢复计时变量 */ TimerCounter=0; break; } } else if(TimerCounter>18/(9+1))/*按下加速键时的处理*/ { /* 恢复计时变量 */ TimerCounter=0; speed0=0; break; } if(bioskey(1)) { key=bioskey(0); if(change(&i,&j,key))/*根据按键值做调整*/ { flag=1; goto end; } } } draw_block(i,j,style,0); renovate(); /*刷新屏幕*/ } if(j==y0) break; j--; draw_block(i,j,style,1); fill_board(i,j,style); sign=1; draw_block(MAPXOFT1,MAPYOFT1,style1,0); style=style1; kill_line(j); /*消去的函数,消去若干行并改变分数和速度*/ while(bioskey(1)) /*清除内存中的按键*/ key=bioskey(0); } setcolor(CYAN); settextstyle(0,0,2); TimerCounter=0; while(1) if(TimerCounter>54) { TimerCounter=0; break; } while(bioskey(1)) /*清除内存中的按键*/ key=bioskey(0); outtextxy(400,340,"Game over!"); outtextxy(360,360,"Enter to replay."); outtextxy(360,380,"Esc to quit."); while(bioskey(1)==0); key=bioskey(0); end:; closegraph(); KillTimer(); if(key==ESC||flag) break; } } void initialize()/*初始化进入图形模式*/ { int gdriver = VGA, gmode=VGAHI, errorcode; /* initialize graphics mode */ initgraph(&gdriver, &gmode, "c://Turboc2"); /* read result of initialization */ errorcode = graphresult(); if (errorcode != grOk) /* an error occurred */ { printf("Graphics error: %s/n", grapherrormsg(errorcode)); printf("Press any key to halt:"); getch(); exit(1); /* return with error code */ } } void init(void)/*初始化游戏板记分器等*/ { int x1; x1=5+MAPXOFT; setcolor(GREEN); circle((x1+0.5)*16,(MAPYOFT-2)*16,3*16); setcolor(WHITE); line((x1-0.6)*16,(MAPYOFT-3.2)*16,x1*16,(MAPYOFT-3.2)*16); line((x1+1.4)*16,(MAPYOFT-3.2)*16,(x1+2.0)*16,(MAPYOFT-3.2)*16); line((x1+0.5)*16,(MAPYOFT-2)*16,(x1+0.5)*16,(MAPYOFT-1.7)*16); circle((x1+0.5)*16,(MAPYOFT-0.9)*16,0.3*16); setcolor(CYAN); line((MAPXOFT+3)*16,(MAPYOFT+21)*16,MAPXOFT*16,(MAPYOFT+23.5)*16); line((MAPXOFT+5.5)*16,(MAPYOFT+21)*16,MAPXOFT*16,(MAPYOFT+26)*16); line((MAPXOFT+9)*16,(MAPYOFT+21)*16,(MAPXOFT+12)*16,(MAPYOFT+23.5)*16); line((MAPXOFT+6.5)*16,(MAPYOFT+21)*16,(MAPXOFT+12)*16,(MAPYOFT+26)*16); setcolor(MAGENTA); ellipse((MAPXOFT+1)*16,(MAPYOFT+11)*16,90,270,7*16,7*16); ellipse((MAPXOFT+11)*16,(MAPYOFT+11)*16,-90,90,7*16,7*16); circle((MAPXOFT+24)*16,(MAPYOFT+6)*16,6*16); setcolor(WHITE); rectangle((x1-0.5)*16,(MAPYOFT-2.9)*16,(x1-0.1)*16,(MAPYOFT-2.5)*16); rectangle((x1+1.5)*16,(MAPYOFT-2.9)*16,(x1+1.9)*16,(MAPYOFT-2.5)*16); setcolor(YELLOW); rectangle(10*16,6*16,20*16,26*16); settextstyle(0,0,2); outtextxy(5*16,13.5*16,"level"); outtextxy(20.4*16,13.5*16,"speed"); outtextxy((MAPXOFT+22)*16,(MAPYOFT+3)*16,"score"); settextstyle(0,0,4); outtextxy(6.5*16,15*16,"0"); outtextxy(21.9*16,15*16,"0"); settextstyle(0,0,3); outtextxy((MAPXOFT+21)*16,(MAPYOFT+6)*16,sc); } void ajustment(void) /*开始游戏前调整速度和高度*/ { int key,boo=1,left=1; setcolor(YELLOW); settextstyle(0,0,2); outtextxy(500,340,"PRESS"); outtextxy(500,360,"ENTER"); outtextxy(500,380," TO "); outtextxy(500,400,"START"); while(1) { if(TimerCounter>8) { TimerCounter=0; boo*=-1; if(boo==-1) setcolor(BLACK); else setcolor(YELLOW); if(left==1) { line(6*16,17*16,8.5*16,17*16); setcolor(BLACK); line(21.4*16,17*16,23.9*16,17*16); } else { line(21.4*16,17*16,23.9*16,17*16); setcolor(BLACK); line(6*16,17*16,8.5*16,17*16); } } if(bioskey(1)) { key=bioskey(0); if(key==UP||key==DOWN) { setcolor(BLACK); settextstyle(0,0,4); outtextxy(6.5*16,15*16,le); outtextxy(21.9*16,15*16,sp); } if(key==ENTER) break; else if(key==UP) { if(left==1) { level--; if(level==-1) level=9; } else { speed--; if(speed==-1) speed=9; } } else if(key==DOWN) { if(left==1) { level++; if(level==10) level=0; } else { speed++; if(speed==10) speed=0; } } else if(key==LEFT||RIGHT) left*=-1; setcolor(YELLOW); sp[0]=speed+'0'; le[0]=level+'0'; settextstyle(0,0,4); outtextxy(6.5*16,15*16,le); outtextxy(21.9*16,15*16,sp); } } setcolor(YELLOW); sp[0]=speed+'0'; le[0]=level+'0'; settextstyle(0,0,4); outtextxy(6.5*16,15*16,le); outtextxy(21.9*16,15*16,sp); setcolor(BLACK); line(21.4*16,17*16,23.9*16,17*16); line(6*16,17*16,8.5*16,17*16); settextstyle(0,0,2); outtextxy(500,340,"PRESS"); outtextxy(500,360,"ENTER"); outtextxy(500,380," TO "); outtextxy(500,400,"START"); } void level_change(void) /*根据高度随机确定方块是否存在*/ { int i,j; setcolor(WHITE); for(i=1;i<=10;i++) for(j=1;j<=level;j++) if(random(2)) { board[i-1][20-j]=1; draw_little_block(i+MAPXOFT,21-j+MAPYOFT); } } void draw_block(int x,int y,int style,int way) /*此x,y为虚拟坐标,为19中形式中的一种:0~18中的一个 x,y为10*20的方格的坐标,下标从1开始 way为1表填充,为0表清除*/ { int x1=x+MAPXOFT,y1=y+MAPYOFT; int i; if(way==1) setcolor(WHITE); else setcolor(BLACK); for(i=0;i<=6;i+=2) draw_little_block(x1+shapes[style].xy[i],y1+shapes[style].xy[i+1]); if(sign==1) sign=0; } void draw_little_block(int x,int y)/*此处仅在10*20的游戏版内画小方块,若在外,不画之。*/ { if((x>=10&&x<20&&y>=6&&y<26)||sign) { rectangle(x*16,y*16,x*16+16,y*16+16); circle(x*16+8,y*16+8,4); } } int check_block(int x,int y,int style)/*此处检查在(x,y)处放置一方块是否可以,若是,则返回1,否则返回0*/ { int x1=x+MAPXOFT,y1=y+MAPYOFT; int x2,y2,i; for(i=0;i<=6;i+=2) { x2=x1+shapes[style].xy[i]; y2=y1+shapes[style].xy[i+1]; if(x2>=10&&x2<20&&y2<26&&(y2<6||board[x2-10][y2-6]==0)) continue; else break; } if(i==8) return 1; else return 0; } void speed_change(void) /*此为变速函数,当分数超过一级时,即加一。*/ { if(score>=(sp[0]-'0')*100&&(sp[0]-'0')<9) { settextstyle(0,0,4); setcolor(BLACK); outtextxy(21.9*16,15*16,sp); sp[0]++; speed++; settextstyle(0,0,4); setcolor(YELLOW); outtextxy(21.9*16,15*16,sp); } } void score_change(int count) /*count为消去的行数,据此来改变score的值*/ { int score_inc[4]={1,3,7,13}; int i; setcolor(BLACK); settextstyle(0,0,3); outtextxy((MAPXOFT+21)*16,(MAPYOFT+6)*16,sc);/*此处将原有的分数盖掉*/ score+=score_inc[count-1]; sc[4]+=score_inc[count-1]; for(i=4;i>=1;i--) { sc[i-1]+=(sc[i]-'0')/10; sc[i]-=(sc[i]-'0')/10*10; } setcolor(YELLOW); settextstyle(0,0,3); outtextxy((MAPXOFT+21)*16,(MAPYOFT+6)*16,sc); /*输出新分数*/ } void kill_line(int y)/*消去的函数,消去若干行并改变分数和速度*/ { int count=0,i,t=1,j,k; for(;y>=1&&t<=4;y--,t++) { for(i=1;i<=10;i++) if(!board[i-1][y-1]) break; if(i==11) { count++; for(k=1;k<=10;k++) { setcolor(BLACK); draw_little_block(k+MAPXOFT,y+MAPYOFT); } for(j=y-1;j>=1;j--) for(k=1;k<=10;k++) { board[k-1][j]=board[k-1][j-1]; if(board[k-1][j]) { setcolor(BLACK); draw_little_block(k+MAPXOFT,j+MAPYOFT); setcolor(WHITE); draw_little_block(k+MAPXOFT,j+1+MAPYOFT); } } renovate(); delay(10000); y++; } } if(count>0) { setcolor(CYAN); settextstyle(0,0,3); outtextxy(500,370,"Good!"); TimerCounter=0; while(1) if(TimerCounter>3) { TimerCounter=0; break; } setcolor(BLACK); settextstyle(0,0,3); outtextxy(500,370,"Good!"); score_change(count); speed_change(); } } void fill_board(int x,int y, int style) /*当一方块停止时,将中相应的值改为1*/ { int x1,y1,i; for(i=0;i<=6;i+=2) { x1=x+shapes[style].xy[i]; y1=y+shapes[style].xy[i+1]; board[x1-1][y1-1]=1; } } int change(int *i,int *j,int key)/*控制方块移动、变形的函数*/ { int key1; if(key==UP&&check_block(*i,*j,shapes[style].next)) { draw_block(*i,*j,style,0); style=shapes[style].next; draw_block(*i,*j,style,1); } else if(key==LEFT&&check_block(*i-1,*j,style)) { draw_block(*i,*j,style,0); (*i)--; draw_block(*i,*j,style,1); } else if(key==RIGHT&&check_block(*i+1,*j,style)) { draw_block(*i,*j,style,0); (*i)++; draw_block(*i,*j,style,1); } else if(key==DOWN&&check_block(*i,*j+1,style)) { draw_block(*i,*j,style,0); (*j)++; draw_block(*i,*j,style,1); speed0=9; } else if(key==ENTER) { while(1) { if(bioskey(1)) key1=bioskey(0); if(key1==ENTER) break; } } else if(key==ESC) return 1; else if(key==21040) { sign=1; draw_block(MAPXOFT1,MAPYOFT1,style1,0); style1=16; sign=1; draw_block(MAPXOFT1,MAPYOFT1,style1,1); } return 0; } void renovate(void) /*刷新屏幕*/ { int i,j; setcolor(WHITE); for(i=1;i<=10;i++) for(j=1;j<=20;j++) if(board[i-1][j-1]==1) draw_little_block(i+MAPXOFT,j+MAPYOFT); setcolor(YELLOW); rectangle(10*16,6*16,20*16,26*16); }