发表日期:2005年11月12日 已经有3587位读者读过此文
/*这是我在参考别人的的俄罗斯方块的基础上,写的一个单机版火拼俄罗斯方块源程序,*/
/*如果有须要下载可到www.jxnczyp.ys168.com中的个人小程序中下载己编译好的程序*/
/*如果想自己编译要先在DOS输入:bgiobj egavga*/
/*再输入tlib graphics.lib+egavga.obj这样就把你自己的图形驱动程序加到你的小程序中了。只有一个文件也能运行*/
/*这个程序写得有点烂,不过谢天谢地总算能用了。*/
/*如果有什么不清楚的地方,可以回QQ:254849895*/
/**/
/**/
/**/
/**/
/**/
/**/
/**/
/**/
#include<stdlib.h>/**/
#include<graphics.h>/**/
#include<dos.h>/**/
#include<time.h>/**/
#include<stdio.h>/**/
#include<string.h>/**/
#include<bios.h>/**/
#define ESC 0x11b
#define ANUM1 0x231
#define ANUM2 0x332
#define BNUM1 0x4f31
#define BNUM2 0x5032
#define LEFTA 0x1e61
#define RIGHTA 0x2064
#define UPA 0x1177
#define ADDOWN 0x3920
#define ACHANG 0x266c
#define LEFTB 0x4b00
#define RIGHTB 0x4d00
#define UPB 0x4800
#define BDDOWN 0x5230
#define BCHANG 0x1c0d
struct Map_Type{/*定义地图,type为类形:当其它 1为一般的方块,2为加行的道具。3为减行的道具,4为加速道具。5为减速道具*/
int type;
int num;
}map[2][22][12],tool[2][12];/**/
int Block_Type[7][4][4]={/*定义七种基本方块类型*/
{{0,0,0,0},{0,1,0,0},{0,1,0,0},{0,1,1,0}},
{{0,0,0,0},{0,0,1,0},{0,0,1,0},{0,1,1,0}},
{{0,1,0,0},{0,1,0,0},{0,1,0,0},{0,1,0,0}},
{{0,1,0,0},{0,1,1,0},{0,0,1,0},{0,0,0,0}},
{{0,0,1,0},{0,1,1,0},{0,1,0,0},{0,0,0,0}},
{{0,1,1,1},{0,0,1,0},{0,0,0,0},{0,0,0,0}},
{{0,0,0,0},{0,1,1,0},{0,1,1,0},{0,0,0,0}}
};
typedef struct{/**/
int d[4][4];
}Block;
Block AB[2],AB_Temp[2],AB_Next[2];/*AB为正在移动的方块,AB——Next为下一个方块*/
int AB_X[2],AB_Y[2];/*移动方块的位置*/
int AB_Tool_Num[2];/*道具的数目*/
int AB_X0[2]={10,230};/*第一,第二玩家的初始坐标*/
int Speed_AB[2],Score_AB[2];/*速度和分数*/
/**/
void InitGraph();/*初始化图形*/
void CloseGraph();/*关闭图形*/
void DrawBK();/*画背景*/
void DrawMap(int mode);/*画地图*/
/*当mode=0时对第一玩家进行操作,当mode=1时对第二玩家进行操作*/
void DrawPerBlock(int x1,int y1,int x2,int y2,int ch,int num);/*画每一个具体的方块*/
void DrawSS(int mode);/*显示分数*/
void DrawTool(int mode);/*显示道具*/
void DrawNextBlock(int mode);/*显示下一个方块*/
void DrawBlock(int k,int mode);/*显示下在移动的方块*/
void CreatBlock(Block *src);/*创建新的方块*/
void RotateBlock(Block *src,Block *dest);/*转动方块*/
int CheckMap(int Y,int X,int mode);/*检查地图*/
int CheckBlock(int mode);/*检查方块的位置合格性*/
int IsLife();/*是不结束游戏*/
void InsertOneLineBlock(int mode);/*增加一行*/
void ReduceOneLineBlock(int mode);/*送去一行*/
void CopyBlock(int mode);/*把移动的方块拷贝到地图上*/
void AnotherBlock(int mode);/**/
void DelectBlock(int mode);/*检查是否有该消去的行,*/
void Attack(struct Map_Type t,int mode);/*使用道具*/
void ChangeTool(int mode);/*道具的转换*/
void DelectTool(int mode);/*删除使用过的道具*/
void GameControl();/*主控程序*/
main(){
int i;
InitGraph();
DrawBK();
DrawMap(0);
DrawMap(1);
DrawSS(0);
DrawSS(1);
DrawTool(0);
DrawTool(1);
GameControl();
CloseGraph();
}
void GameControl(){
int key,count=0,i;
CreatBlock(&AB[0]);for(i=0;i<8;i++)delay(5000);/*先创建要显示的方块,和将要显示的方块*/
CreatBlock(&AB[1]);delay(5000);/**/
CreatBlock(&AB_Next[0]);delay(5000);/**/
CreatBlock(&AB_Next[1]);delay(5000);/**/
DrawNextBlock(0);
DrawNextBlock(1);/**/
AB_X[0]=3;AB_Y[0]=-4;/*初始入方块的位置*/
AB_X[1]=3;AB_Y[1]=-4;/**/
while(1){
while(!kbhit()){
DrawBlock(1,0);/*显示方块*/
DrawBlock(1,1);/**/
for(i=0;i<4;i++)delay(5000);/**/
DrawBlock(0,0);/*擦去方块*/
DrawBlock(0,1);/**/
count++;/**/
if((count%(10-Speed_AB[0]))==0)AB_Y[0]++;/**/
if((count%(10-Speed_AB[1]))==0)AB_Y[1]++;/**/
if((count%((10-Speed_AB[0])*(10-Speed_AB[1])))==0)count=0;/**/
for(i=0;i<2;i++){/**/
if(!CheckBlock(i)){/*如果移动方块不合格就把下一个广场给移动方块*/
AnotherBlock(i);/**/
}
}
}
key=bioskey(0);/*取得按键值*/
switch(key){
case ESC:/**/
CloseGraph();
break;
case LEFTA:/*向左*/
AB_X[0]--;
if(!CheckBlock(0))AB_X[0]++;
break;
case LEFTB:
AB_X[1]--;
if(!CheckBlock(1))AB_X[1]++;
break;
case RIGHTA:/*向右*/
AB_X[0]++;
if(!CheckBlock(0))AB_X[0]--;
break;
case RIGHTB:
AB_X[1]++;
if(!CheckBlock(1))AB_X[1]--;
break;
case UPA:/*转动方块*/
AB_Temp[0]=AB[0];
RotateBlock(&AB[0],&AB_Temp[1]);
AB[0]=AB_Temp[1];
if(!CheckBlock(0))AB[0]=AB_Temp[0];
break;
case UPB:
AB_Temp[0]=AB[1];
RotateBlock(&AB[1],&AB_Temp[1]);
AB[1]=AB_Temp[1];
if(!CheckBlock(1))AB[1]=AB_Temp[0];
break;
case ADDOWN:/*让方块直接下落*/
for(;CheckBlock(0);){
DrawBlock(1,0);
DrawBlock(0,0);
AB_Y[0]++;
}
AnotherBlock(0);
break;
case BDDOWN:
for(;CheckBlock(1);){
DrawBlock(1,1);
DrawBlock(0,1);
AB_Y[1]++;
}
AnotherBlock(1);
break;
case ANUM1:/*对自己使用道具*/
if(AB_Tool_Num[0]>0){
Attack(tool[0][0],0);
DelectTool(0);
}
DrawTool(0);
DrawSS(0);
break;
case BNUM1:
if(AB_Tool_Num[1]>0){
Attack(tool[1][0],1);
DelectTool(1);
}
DrawTool(1);
DrawSS(1);
break;
case ANUM2:/*对对手使用道具*/
if(AB_Tool_Num[0]>0){
Attack(tool[0][0],1);
DelectTool(0);
}
DrawTool(0);
DrawSS(1);
break;
case BNUM2:
if(AB_Tool_Num[1]>0){
Attack(tool[1][0],0);
DelectTool(1);
}
DrawTool(1);
DrawSS(0);
break;
case ACHANG:/*道具转换*/
ChangeTool(0);
break;
case BCHANG:
ChangeTool(1);
break;
}
if(IsLife()) CloseGraph();/*是不结束游戏*/
}
}
int CheckMap(int Y,int X,int mode){
if(X<0||X>=12||Y>22||Y<0) return 0;/*地图是是否有方块*/
return map[mode][Y][X].type;
}
int CheckBlock(int mode){
int i,j,m,n;
for(i=3;i>=0;i--){
for(j=0;j<4;j++){
m=i+AB_Y[mode];
n=j+AB_X[mode];
if(AB[mode].d[i][j]&&(n<0||n>=12||(m==21)))return 0;/*方块是否出了地图外面*/
if(CheckMap(m+1,n,mode)&&AB[mode].d[i][j]) return 0;/*判断下一个位置的地图上是否有方块是*/
}
}
return 1;
}
void DelectTool(int mode){
int i;
for(i=0;i<AB_Tool_Num[mode]-1;i++){
tool[mode][i]=tool[mode][i+1];
}
tool[mode][AB_Tool_Num[mode]-1].type=0;/**/
tool[mode][AB_Tool_Num[mode]-1].num=0;
AB_Tool_Num[mode]--;
}
void ChangeTool(int mode){
int i;
struct Map_Type t;
t=tool[mode][0];
for(i=0;i<AB_Tool_Num[mode]-1;i++){
tool[mode][i]=tool[mode][i+1];
}
tool[mode][AB_Tool_Num[mode]-1]=t;
DrawTool(mode);
}
void Attack(struct Map_Type t,int mode){
int i;
switch(t.type){
case 2:/*增加几行*/
for(i=0;i<t.num;i++){
InsertOneLineBlock(mode);
}
break;
case 3:/*减去几行*/
for(i=0;i<t.num;i++){
ReduceOneLineBlock(mode);
}
break;
case 4:/*加速*/
if((Speed_AB[mode]+t.num)<=10)Speed_AB[mode]++;
break;
case 5:/*减速*/
if((Speed_AB[mode]-t.num)>0)Speed_AB[mode]--;
break;
}
}
void DelectBlock(int mode){
int i,j,count=0,sum=0,k=0;
for(i=21;i>=0;i--){
count=0;
for(j=0;j<12;j++){/*检查是否该消去*/
if(map[mode][i][j].type)count++;/**/
}
if(count==12){/*该消去*/
for(k=i;k>0;k--){
for(j=0;j<12;j++){/*把地图上的道具给道具数组,并往下移一行*/
if(map[mode][i][j].type>1&&AB_Tool_Num[mode]<12&&(k==i)){
tool[mode][AB_Tool_Num[mode>=map[mode][i][j];
AB_Tool_Num[mode]++;
}
map[mode][k][j]=map[mode][k-1][j];
}
}
Score_AB[mode]+=12;/*加分*/
sum++;/*统计消去几行*/
i++;/*使往下一行后,行坐标仍指向这行*/
}
for(j=0;j<12;j++){
map[mode][0][j].type=0;
map[mode][0][j].num=0;
}
}
mode=1-mode;/*把操作模式变成对对方mode=0为第一玩家,mode=1为第二玩家*/
if(sum>=3){/*如果消去3行以上就给对广场增加一行*/
for(i=0;i<sum-1;i++){
InsertOneLineBlock(mode);
}
}
mode=1-mode;/*把操作模式转给自己*/
randomize();
k=random(6);/*根据你消去的行数来设置产生道具的概率*/
if(k<sum){/**/
do{
i=random(22);
j=random(12);
}while(map[mode][i][j].type!=1);
count=random(4)+2;/*产生道具类型*/
sum=random(3)+1;/**/
map[mode][i][j].type=count;/**/
map[mode][i][j].num=sum;
}
DrawMap(mode);
DrawTool(mode);
DrawSS(mode);
}
void AnotherBlock(int mode){
CopyBlock(mode);
DrawMap(mode);
DelectBlock(mode);
AB[mode]=AB_Next[mode];
CreatBlock(&AB_Next[mode]);
DrawNextBlock(mode);
AB_X[mode]=3;/*重新定义方块位置*/
AB_Y[mode]=-4;/**/
}
int IsLife(){
int i,j;
for(i=0;i<2;i++){
for(j=0;j<12;j++){/**/
if(map[i][1 ][j].type){
return 1;
}
}
}
return 0;
}
void CopyBlock(int mode){
int i,j,m,n;
for(i=0;i<4;i++){/*如果有方块就拷到地图上*/
for(j=0;j<4;j++){
m=i+AB_Y[mode];
n=j+AB_X[mode];
if(AB[mode].d[i][j]&&m>=0&&m<22&&n>=0&&n<12){
map[mode][m][n].type=1;
map[mode][m][n].num=0;
}
}
}
}
void ReduceOneLineBlock(int mode){
int i,j;
for(i=21;i>0;i--){
for(j=0;j<12;j++){
map[mode][i][j]=map[mode][i-1][j];
}
}
for(j=0;j<12;j++){
map[mode][0][j].type=0;
map[mode][0][j].num=0;
}
DrawMap(mode);
}
void InsertOneLineBlock(int mode){
int i,j;
for(i=0;i<21;i++){
for(j=0;j<12;j++){
map[mode][i][j]=map[mode][i+1][j];
}
}
i=(map[mode][21][0].type>0)?1:0;
for(j=0;j<12;j++){
map[mode][21][j].type=0;
map[mode][21][j].num=0;
}
for(j=i;j<12;j+=2){
map[mode][21][j].type=1;
map[mode][21][j].num=0;
}
DrawMap(mode);
}
void DrawBlock(int k,int mode){
register int i,j;
int x1,y1,x2,y2;
for(i=0;i<4;i++){
for(j=0;j<4;j++){
x1=(AB_X[mode]+j)*12+AB_X0[mode]+1;/*算出方块中每一个小方块的具体坐标*/
y1=(AB_Y[mode]+i)*12+21;
x2=x1+10;
y2=y1+10;
if(y1>20&&k&&AB[mode].d[i][j]){/*当K=1时显示方块*/
DrawPerBlock(x1,y1,x2,y2,1,0);
}
if(y1>20&&(k==0)&&AB[mode].d[i][j]){/*当k=0时擦去方块*/
DrawPerBlock(x1,y1,x2,y2,0,0);
}
}
}
}
void RotateBlock(Block *src,Block *dest){/*转动方块*/
int i,j;
for(i=0;i<4;i++){
for(j=0;j<4;j++){
dest->d[j][i]=src->d[i][3-j];
}
}
}
void CreatBlock(Block *src){
int i,j,k;
randomize();
k=random(7);
for(i=0;i<4;i++){/*随机产生是七种方块中的一种*/
for(j=0;j<4;j++){
src->d[i][j]=Block_Type[k][i][j];
}
}
i=random(4);
for(;i>0;i--,*src=AB_Temp[0]){/*随机转动0~3次*/
RotateBlock(src,&AB_Temp[0]);
}
}
void DrawNextBlock(int mode){
int i,j,x1,y1=20,x2,y2=78;
x1=154+AB_X0[mode];
x2=x1+58;
setcolor(LIGHTCYAN);
setfillstyle(SOLID_FILL,BLACK);
rectangle(x1,y1,x2,y2);
for(i=0;i<4;i++){
for(j=0;j<4;j++){/*算出每一个小方块的具体坐标,并画出*/
x1=j*12+160+AB_X0[mode];
y1=i*12+26;
x2=x1+10;
y2=y1+10;
DrawPerBlock(x1,y1,x2,y2,AB_Next[mode].d[i][j],0);
}
}
}
void DrawTool(int mode){/*显示道具*/
int i,x1,y1=294,x2,y2=306;
x1=AB_X0[mode];
x2=x1+144;
setcolor(GREEN);
setfillstyle(SOLID_FILL,BLACK);
rectangle(x1,y1,x2,y2);
bar(x1+1,y1+1,x2-1,y2-1);
for(i=0;i<AB_Tool_Num[mode];i++){
x1=i*12+1+AB_X0[mode];
x2=x1+10;
y1=295;
y2=305;
DrawPerBlock(x1,y1,x2,y2,tool[mode][i].type,tool[mode][i].num);
}
}
void DrawSS(int mode){/*显示分数和速度*/
int x1,y1,x2,y2;
char str[6];
setcolor(CYAN);
setfillstyle(SOLID_FILL,BLACK);
x1=AB_X0[mode]+154;
x2=x1+58;
y1=88;
y2=136;
rectangle(x1,y1,x2,y2);
bar(x1+1,y1+1,x2-1,y2-1);
setcolor(WHITE);
outtextxy(x1+5,y1+1,"score");
sprintf(str,"%d",Score_AB[mode]);
outtextxy(x1+5,y1+13,str);
outtextxy(x1+5,y1+25,"speed");
sprintf(str,"%d",Speed_AB[mode]);
outtextxy(x1+5,y1+37,str);
}
void DrawPerBlock(int x1,int y1,int x2,int y2,int ch,int num){
char str[4];
setcolor(BLACK);
setfillstyle(SOLID_FILL,WHITE);/*产生立休效果*/
bar(x1,y1,x2,y2);
setfillstyle(SOLID_FILL,DARKGRAY);/**/
bar(x1+1,y1+1,x2,y2);
strcpy(str," ");
switch(ch){
case 0:
setfillstyle(SOLID_FILL,BLACK);
break;
case 1:
setfillstyle(SOLID_FILL,BROWN);
break;
case 2:
setfillstyle(SOLID_FILL,RED);
sprintf(str,"%d",num);
break;
case 3:
setfillstyle(SOLID_FILL,BLUE);
sprintf(str,"%d",num);
break;
case 4:
setfillstyle(SOLID_FILL,LIGHTRED);
str[0]=0x18;/*产生向上方向,向上加速*/
break;
case 5:
setfillstyle(SOLID_FILL,LIGHTBLUE);
str[0]=0x19;/*产生向下方向,向下减速*/
break;
}
setcolor(WHITE);
bar(x1+1,y1+1,x2-1,y2-1);
outtextxy(x1+2,y1+2,str);
if(ch==0){
setfillstyle(SOLID_FILL,BLACK);
bar(x1,y1,x2,y2);
}
}
void DrawMap(int mode){/*显示地图*/
int i,j,x1,y1=20,x2,y2=284;
x1=AB_X0[mode];
x2=x1+144;
setcolor(YELLOW);
setfillstyle(SOLID_FILL,BLACK);
rectangle(x1,y1,x2,y2);
for(i=0;i<22;i++){
for(j=0;j<12;j++){
x1=j*12+1+AB_X0[mode];
y1=i*12+21;
x2=x1+10;
y2=y1+10;
DrawPerBlock(x1,y1,x2,y2,map[mode][i][j].type,map[mode][i][j].num);
}
}
}
void DrawBK(){/*画背景*/
int x1,y1,x2,y2;
x1=getmaxx();
x1=(getmaxx()-452)/2;
x2=x1+452;
y1=getmaxy();
y1=(getmaxy()-316)/2;
y2=y1+316;
setbkcolor(BLACK);
setcolor(LIGHTBLUE);
setviewport(x1,y1,x2,y2,1);
rectangle(0,0,452,316);
rectangle(2,+2,450,314);
setcolor(RED);
outtextxy(180,6,"FIRE RUSS");
}
void InitGraph(){
int driver,mode,x,y;
driver=DETECT;
registerbgidriver(EGAVGA_driver);/*把图形驱动程序连到可执行文件中,这样一个文件就可以执行了*/
initgraph(&driver,&mode,"G://program//tc");
x=getmaxx();
y=getmaxy();
if(x<317||y<452){
outtextxy(10,10,"The scree is too small");
getch();
CloseGraph();
}
}
void CloseGraph(){
cleardevice();
outtextxy(50,100,"Thank you for you use this program");
closegraph();
exit(0);
}