上接Maketetris继续:
在Maketetris里,一共有19个case,第一个case是田字格的形态,田字格有且只有一种形态,我们在Printtetris里面,已经将b数组,也就是方块数组全部赋值为1,而且中心方块一直是4X4大方块里第三行第二个方块,它的xy坐标不用动,所以不需要在写代码的时候再写19次,所以一开始即可对a[80][80] 定位数组赋值了,a数组具体怎么用这里还讲不清楚,后面用到的函数会讲到。每个case 都会有b1,b2,b3数组来赋值,赋值为1
void CleanTetris(struct Tetris*tetris);
void CleanTetris(struct Tetris*tetris)
{
for(i=0;i<4;i++)
{
b[i]=0;
}
MakeTetris(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(" ");
}
}
}
}
与Printtetris类似,不过Clean函数里将b数组全部赋值为0,因为是要清除上一时间点方块的痕迹,不然看起来会很糟糕,同样里面调用了MakeTetris函数,因为具体需要如何清除痕迹,需要由每个链表节点(方块)的flag(方块的形态共19种)来判定,与Printtetris很类似。
int ifMove(struct Tetris*);
int ifMove(struct Tetris*tetris)
{
if(a[tetris->x][tetris->y]!=0)
{
return 0;
}
else
{
if((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) ) ||
(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-1]==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==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==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==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==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==19&&(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==17&&(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;
}
ifMove 需要说的一点是,每当调用ifMove之前,方块的xy坐标都会先发生改变,向左向右,或是加速向下,然后用ifMove判断,已经改变的中心坐标,是否在以中心方块坐标为中心方块的4X4方块里面,是否符合相应的flag形态,如果符合 return1,如果不符合return 0,可以看到先判断的是:
if(a[tetris->x][tetris->y]!=0)
{
return 0;
}
先判断的是中心方块,同理,不需要19个形态一次一次判断,如果连中心方块都不能放入,肯定不可能放入,a数组在这里的作用就是去判断是否在已经改变的中心坐标位置上,是否有方块,a数组就是一个定位作用。(以上代码的xy坐标都是被提前“试着改过”的,如果ifMove返回0,都会进行还原)。
为了方便理解,用flag1 作为例子:
void Del_Fullline(struct Tetris*tetris);
void Del_Fullline(struct Tetris*tetris)
{
int k,del_rows=0;
for(j=FrameY+Frame_height-1;j>=FrameY+1;j--)//定位于下边框至上边框
{
k=0;
for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)//定位于左边框至右边框
{
if(a[i][j]==1)
{
k++;
if(k==Frame_width-2)//如果满行
{
for(k=FrameX+2;k<FrameX+2*Frame_width-2;k+=2)//进行清行操作
{
a[k][j]=0;
gotoxy(k,j);
printf(" ");
}
for(k=j-1;k>FrameY;k--)//清完一行,被清行上面一行或N行需要集体落下
{
for(i=FrameX+2;i<FrameX+2*Frame_width-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++;//用来计算分数
}
}
}
}
score+=100*del_rows;//每清一行,加100分
if(del_rows>0&&(score%1000==0||score/1000>level-1))
{
speed-=30;//当每满1000分的时候,延迟速度减少30毫秒
level++;//恭喜你升级1级
}
}
这是判断是否满行的函数,也是每个方块落定以后需要判定的,照着注释很好理解。
void Regulation();
void explantion();
void Replay();
void welcome();
void title();
void flower();
void closer();
int color();
void explantion();
以上几个函数,几乎没有用到任何参数,基本上都是定位和打印,以下是图片和源代码:
void Regulation()
{
int i,j=1;
system("cls");
color(13);
gotoxy(34,3);
printf("Regulation");
color(2);
for(i=6;i<=18;i++)
{
for(j=12;j<=70;j++)
{
gotoxy(j,i);
if(i==6||i==18) printf("=");
else if(j==12||j==69) printf("=");
}
}
color(12);
gotoxy(16,7);
printf("tip1:不同形状的小方块从屏幕上方落下,玩家通过调整");
gotoxy(22,9);
printf("方块的位置和方向,使他们在屏幕拼出完整的");
gotoxy(22,11);
printf("一条或者几条");
color(14);
gotoxy(16,13);
printf("tip2:每消除一行,积分涨100");
color(11);
gotoxy(16,15);
printf("tip3:每累计1000分,会提升一个等级");
color(10);
gotoxy(16,17);
printf("tip4:提升等级会使方块下落速度加快,游戏难度加大");
getch();
system("cls");
welcome();
}
void explantion()
{
int i,j=1;
system("cls");
color(13);
gotoxy(32,3);
printf("explanation");
color(2);
for(i=6;i<=16;i++)
{
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:玩家可以通过方向键来移动方块");
color(10);
gotoxy(18,9);
printf("tip2:通过向上键旋转方块");
color(14);
gotoxy(18,11);
printf("tip3:通过向下键加速方块下落");
color(11);
gotoxy(18,13);
printf("tip4:按空格键暂停游戏");
color(4);
gotoxy(18,15);
printf("tip5:按ESC键退出游戏");
getch();
system("cls");
main();
}
void Replay()
{
system("cls");
memset(a,0,6400*sizeof(int));
DrawGameframe();
Gameplay();
}
void welcome()
{
int n;
int i,j=1;
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(25,17);
printf("3.游戏规则");
gotoxy(40,17);
printf("4.退出");
gotoxy(21,22);
color(3);
printf("请选择【1 2 3 4】:[ ]\b\b");
color(14);
scanf("%d",&n);
switch(n)
{
case 1:
system("cls");
DrawGameframe();
Gameplay();
break;
case 2:
explantion();
break;
case 3:
Regulation();
break;
case 4:
closer();
break;
}
}
void title()
{
color(15);
gotoxy(28,3);
printf("俄 罗 斯 方 块\n");
color(11);
gotoxy(18,5);
printf("▇");
gotoxy(18,6);
printf("▇▇");
gotoxy(18,7);
printf("▇");
color(14);
gotoxy(26,6);
printf("▇▇");
gotoxy(28,7);
printf("▇▇");
color(10);
gotoxy(36,6);
printf("▇▇");
gotoxy(36,7);
printf("▇▇");
color(13);
gotoxy(45,5);
printf("▇");
gotoxy(45,6);
printf("▇");
gotoxy(45,7);
printf("▇");
gotoxy(45,8);
printf("▇");
color(12);
gotoxy(56,6);
printf("▇");
gotoxy(52,7);
printf("▇▇▇");
}
void flower()
{
gotoxy(66,11);
color(12);
printf("(_)");
gotoxy(64,12);
printf("(_)");
gotoxy(68,12);
printf("(_)");
gotoxy(66,13);
printf("(_)");
gotoxy(67,12);
color(6);
printf("@");
gotoxy(72,10);
color(13);
printf("(_)");
gotoxy(76,10);
printf("(_)");
gotoxy(74,9);
printf("(_)");
gotoxy(74,11);
printf("(_)");
gotoxy(75,10);
color(6);
printf("@");
gotoxy(71,12);
printf("|");
gotoxy(72,11);
printf("/");
gotoxy(70,13);
printf("\\|");
gotoxy(70,14);
printf("^|/");
gotoxy(70,15);
printf("\\|");
gotoxy(71,16);
printf("|/");
gotoxy(71,17);
printf("|");
gotoxy(67,17);
color(10);
printf("\\\\\\\\");
gotoxy(73,17);
printf("//");
gotoxy(67,18);
color(2);
printf("^^^^^^^^");
}
void closer()
{
exit(0);
}
int color(int c)
{
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),c);
return 0;
}
第三部分是最关键的 CreateFlag和Gameplay函数