目录
前言
例如:本篇文章将记录俄罗斯方块的详细制作过程及所遇到的问题、解决方法。步骤分为:1、打印静态背景边框;2、显示动态图形、控制光标位置及隐藏光标;3、将到第的动态图形添加到静态背景图中,并且画新的动态图形;4、添加键盘按键,控制动态图形向左向右、向下移动;5、消行、增加分数及游戏难度水平控制功能;6、动态功能变换及游戏结束判断功能。
提示:以下是本篇文章正文内容,下面案例可供参考
一、项目源代码
1.1 开发环境
Visual Studio 2012 开发语言是C语言
1.2 俄罗斯方块源码
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdlib.h>
struct coord
{
int x;//x坐标
int y;//y坐标
};
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
void gotoxy(int x,int y);//控制光标的位置
void hideCursor();//隐藏光标
void drawDynamicShape();//画动态图形
void showDynamicShape();//打印动态图形
void moveDown();//向下移动
void addStaticMap();//添加到静态背景图中
void moveLeft();//向左移动
void moveRight();//向右移动
void clearFullLine();//清除满行
int isFullOneLine(int line);//判断line行是不是满行
void clearOneLine(int line);//清除当前的line满行
void addLevel();//增加游戏难度水平
void changeShape();//变形
int isCrash(int n1,int x1,int y1,int n2, int x2,int y2,int n3, int x3,int y3);
int isGameOver();//判断游戏是否结束
//全局变量
int score = 0;//游戏分数
int level = 1;//游戏难度水平
int speed = 20;//用来控制下落速度
int currentShape;//用来保存当前图形的编号
int map[21][12];//保存静态背景图
struct coord shape[4];//保存了图形的四个坐标点
int main()
{
int i;
char input;//用来保存输入的按键
srand(time(NULL));//初始化随机种子
initMap();//初始化边框
drawDynamicShape();//画动态图形,对四个坐标点赋值
while(1)
{
if(isGameOver())
{
return;//将main函数结束,整个程序结束
}
showStaticMap();//打印静态图
showDynamicShape();//打印动态图形
moveDown();//向下移动
for(i = 0; i < speed; i++)
{
if(_kbhit())//检测是否有按键产生
{
input = _getch();
if(input == 'a')
{
/*printf("向左移动");*/
moveLeft();
input = 0;
}
else if(input == 'd')
{
/*printf("向右移动");*/
moveRight();
input = 0;
}
else if(input == 'w')
{
/*printf("变形");*/
changeShape();
input = 0;
}
else if(input == 's')
{
/*printf("向下移动");*/
moveDown();
input = 0;
}
}
Sleep(50);
}
}
getchar();
return 0;
}
//判断游戏是否结束,结束返回1,不结束返回0
int isGameOver()
{
int j;
if(isFullOneLine(0))//如果第0行,是满行,清空
{
for(j = 1; j <= 10; j++)
{
map[0][j] = 0;
}
}
for(j = 1; j <= 10; j++)
{
if(map[0][j] != 0)//说明出现2,有障碍
return 1;//游戏结束
}
return 0;//游戏未结束
}
//碰撞检测函数
//int center //代表的是中心点,在结构体数组中的下标
//三对x y,代表的除了中心点以外,其他点的变化值
//如果碰撞返回值是1,不碰撞返回值是0
int isCrash(int n1,int x1,int y1,int n2, int x2,int y2,int n3, int x3,int y3)
{
//(0,-1) (0,1) (0,-2)
if(map[shape[n1].y+y1][shape[n1].x+x1] != 0 || map[shape[n2].y+y2][shape[n2].x+x2] || map[shape[n3].y+y3][shape[n3].x+x3])
{
return 1;
}
return 0;
}
//变形函数
void changeShape()
{
//在变形之前,一定要判断当前是什么图形
switch(currentShape)//先判断当前图形
{
case 1://横条
if(isCrash(0,0,-1,2,0,1,3,0,2))//发生碰撞
return;
shape[0].x = shape[1].x;
shape[0].y = shape[1].y-1;
shape[2].x = shape[1].x;
shape[2].y = shape[1].y+1;
shape[3].x = shape[1].x;
shape[3].y = shape[1].y+2;
currentShape = 2;//改为2,因为变形后,此时的图形是竖条
break;
case 2://竖条
if(isCrash(0,-1,0,2,1,0,3,2,0))//如果碰撞,函数结束
return;
shape[0].x = shape[1].x-1;
shape[0].y = shape[1].y;
shape[2].x = shape[1].x+1;
shape[2].y = shape[1].y;
shape[3].x = shape[1].x+2;
shape[3].y = shape[1].y;
currentShape = 1;//改为1,因为变形后,此时的图形是横条
break;
}
}
//增加游戏难度水平的函数
void addLevel()
{
if(score >= 500 && level == 1)
{
speed -= 5;
level = 2;
}
else if(score >= 2000 && level == 2)
{
speed -= 5;
level = 3;
}
else if(score >= 5000 && level == 3)
{
speed -= 5;
level = 4;
}
}
//判断第line行是不是满行,是满行返回1,不是返回0
int isFullOneLine(int line)
{
int j;
for(j = 1; j <= 10; j++)
{
if(map[line][j] == 0)//说明line不是满行
return 0;//0代表不是满行
}
//程序如果能执行到这,说明没有执行过return 0
return 1;//代表是满行
}
//清除单行满行
void clearOneLine(int line)
{
int i,j;
for(i = line; i > 0; i--)
{
for(j = 1; j <= 10; j++)
{
map[i][j] = map[i-1][j];
}
}
}
//消除满行
void clearFullLine()
{
int i;
for(i = 19; i > 0; i--)
{
//1.判断每一行i是不是满行
if(isFullOneLine(i))//返回值是1,说明是满行 1代表真
{
//2.消除当前的满行i
clearOneLine(i);
score += 100;
//3.增加游戏难度水平
addLevel();
i++;//避免出现连续的两个满行有bug
}
}
}
//向左移动
void moveLeft()
{
int i;
//先要进行条件判断,判断是否能够向左移动
for(i = 0; i < 4; i++)
{
if(map[shape[i].y][shape[i].x-1] != 0)//碰到障碍物或边框
{
return;//结束函数
}
}
//向左移动
for(i = 0; i < 4; i++)
{
shape[i].x--;
}
}
//向右移动
void moveRight()
{
int i;
//先要进行条件判断,判断是否能够向右移动
for(i = 0; i < 4; i++)
{
if(map[shape[i].y][shape[i].x+1] != 0)//碰到障碍物或边框
{
return;//结束函数
}
}
//向右移动
for(i = 0; i < 4; i++)
{
shape[i].x++;
}
}
//将动态图形添加到静态背景图中
void addStaticMap()
{
int i;
for(i = 0; i < 4; i++)
{
map[shape[i].y][shape[i].x] = 2;
}
}
//向下移动
void moveDown()
{
int i;
//先判断能否向下移动
for(i = 0; i < 4; i++)
{//把四个坐标点,当做二维数组的行和列的下标
//x --->列
//y --->行
if(map[shape[i].y+1][shape[i].x] != 0)//y+1判断下一个位置是不是碰到障碍
{
//将动态图形添加到静态背景图中
addStaticMap();
//进行消除满行的操作
clearFullLine();
//再次生成一个新的图形,再画一个图形
drawDynamicShape();
return;//函数结束,说明落到了最底下
}
}
//实现让图形向下移动一个位置
for(i = 0; i < 4; i++)
{
shape[i].y++;
}
}
//打印动态图形
void showDynamicShape()
{
int i;
for(i = 0; i < 4; i++)
{
gotoxy(shape[i].x*2,shape[i].y);
printf("■");
}
}
//画动态图形
void drawDynamicShape()
{
currentShape = rand()%3;//生成一个随机图形,%几,取决于你的图形库的个数
switch(currentShape)
{
case 0:
shape[0].x = 5;//田字格
shape[0].y = 0;
shape[1].x = 6;
shape[1].y = 0;
shape[2].x = 5;
shape[2].y = 1;
shape[3].x = 6;
shape[3].y = 1;
break;
case 1:
shape[0].x = 4;//横条
shape[0].y = 0;
shape[1].x = 5;
shape[1].y = 0;
shape[2].x = 6;
shape[2].y = 0;
shape[3].x = 7;
shape[3].y = 0;
break;
case 2:
shape[0].x = 5;//竖条
shape[0].y = 0;
shape[1].x = 5;
shape[1].y = 1;
shape[2].x = 5;
shape[2].y = 2;
shape[3].x = 5;
shape[3].y = 3;
break;
}
}
//初始化静态背景边框
void initMap()
{
int i,j;
hideCursor();//隐藏光标
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(j == 0 || j == 11 || i == 20)
map[i][j] = 1;
else
map[i][j] = 0;
}
}
}
//打印静态背景图
void showStaticMap()
{
int i,j;
gotoxy(0,0);//每次打印边框前,将光标移动到坐标原点
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(map[i][j] == 0) //打印空格
{
printf(" ");//两个空格,是因一个星星的宽度占两个位置
}
else if(map[i][j] == 1)//打印边框
{
printf("★");
}
else if(map[i][j] == 2)//打印图形
{
printf("■");
}
}
printf("\n");
}
printf("score:%d level:%d\n",score,level);
}
//控制光标位置
void gotoxy(int x,int y)
{ //让printf,回到x, y点,x, y是坐标,如果打印位置到原点,x 0,y 0,,gotoxy(0, 0);
int z=0x0b;
HANDLE hOutput;
COORD loc;
loc.X = x; loc.Y=y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
}
//隐藏光标
void hideCursor()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = 0; //隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
}
二、打印静态背景边框
2.1 初始化静态背景边框
定义一个全局的二维数组map[21][12] ,两层for循环嵌套将第0列、第11列和第20行赋值为1,其余初始化为0
2.2 打印静态背景边框
将数组map[21][12]中为0的 printf(" ") 两个空格,为1的打印一个星星"★" 分别将初始化背景边框与显示背景边框封装成一个函数,并且在主函数main中调用
#include <stdio.h>
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
//全局变量
int map[21][12];//保存静态背景图
int main()
{
initMap();
showStaticMap();
getchar();
return 0;
}
//初始化静态背景边框
void initMap()
{
int i,j;
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(j == 0 || j == 11 || i == 20)
map[i][j] = 1;
else
map[i][j] = 0;
}
}
}
//打印静态背景图
void showStaticMap()
{
int i,j;
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(map[i][j] == 0)
{
printf(" ");//两个空格,是因一个星星的宽度占两个位置
}
else if(map[i][j] == 1)
{
printf("★");
}
}
printf("\n");
}
}
三、顶部显示动态图形
3.1 画一个动态图形
全局定义一个结构体,用来保存x坐标、y坐标,并且定义一个结构体数组,用来保存动态图形的4个坐标点,根据数组map[21][12] 在设置动态图形的位置
3.2 打印动态图形
添加windows.h 头文件,调用gotoxy控制光标位置、hideCursor隐藏光标,使用for循环,每次依次移动4个坐标点
#include <stdio.h>
#include <windows.h>
struct coord
{
int x;//x坐标
int y;//y坐标
};
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
void gotoxy(int x,int y);//控制光标的位置
void hideCursor();//隐藏光标
void drawDynamicShape();//画动态图形
void showDynamicShape();//打印动态图形
//全局变量
int map[21][12];//保存静态背景图
struct coord shape[4];//保存了图形的四个坐标点
int main()
{
initMap();//初始化边框
drawDynamicShape();//画动态推行
showStaticMap();//打印静态图
showDynamicShape();//打印动态图形
/*
gotoxy(8,0);//光标移动到10,10
printf("■");
gotoxy(10,0);
printf("■");
gotoxy(12,0);
printf("■");
gotoxy(14,0);
printf("■");
*/
getchar();
return 0;
}
//打印动态图形
void showDynamicShape()
{
int i;
for(i = 0; i < 4; i++)
{
gotoxy(shape[i].x*2,shape[i].y);
printf("■");
}
}
//画动态图形
void drawDynamicShape()
{
shape[0].x = 4;
shape[0].y = 0;
shape[1].x = 5;
shape[1].y = 0;
shape[2].x = 6;
shape[2].y = 0;
shape[3].x = 7;
shape[3].y = 0;
}
//初始化静态背景边框
//打印静态背景图
//控制光标位置
void gotoxy(int x,int y)
{ //让printf,回到x, y点,x, y是坐标,如果打印位置到原点,x 0,y 0,,gotoxy(0, 0);
int z=0x0b;
HANDLE hOutput;
COORD loc;
loc.X = x; loc.Y=y;
hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleCursorPosition(hOutput, loc);
}
//隐藏光标
void hideCursor()
{
HANDLE handle = GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_CURSOR_INFO CursorInfo;
GetConsoleCursorInfo(handle, &CursorInfo);//获取控制台光标信息
CursorInfo.bVisible = 0; //隐藏控制台光标
SetConsoleCursorInfo(handle, &CursorInfo);//设置控制台光标状态
}
四、向下移动、添加静态背景图、产生新的图形
4.1 线下移动
因为map[21][12] 中21为行数、12为列数,所以人行数变化就何以了
4.2 动态图形添加到静态背景图中
在向下移动中,要先判断下一行的是否为0,如果不为0则不再向下移动,并且把结构体的4个点赋值为2,在打印静态背景图时将为2的图形显示出来
4.3 产生新的动态图形
在向下移动图形时,如果判断下一行不为0时,将调用打印动态图形的函数进行调用
#include <stdio.h>
#include <windows.h>
struct coord
{
int x;//x坐标
int y;//y坐标
};
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
void gotoxy(int x,int y);//控制光标的位置
void hideCursor();//隐藏光标
void drawDynamicShape();//画动态图形
void showDynamicShape();//打印动态图形
void moveDown();//向下移动
//全局变量
int map[21][12];//保存静态背景图
struct coord shape[4];//保存了图形的四个坐标点
int main()
{
initMap();//初始化边框
drawDynamicShape();//画动态图形,对四个坐标点赋值
while(1)
{
showStaticMap();//打印静态图
showDynamicShape();//打印动态图形
moveDown();//向下移动
Sleep(1000);//延时1000毫秒
}
getchar();
return 0;
}
//向下移动
void moveDown()
{
int i;
//先判断能否向下移动
for(i = 0; i < 4; i++)
{//把四个坐标点,当做二维数组的行和列的下标 x --->列 y --->行
if(map[shape[i].y+1][shape[i].x] != 0)//y+1判断下一个位置是不是碰到障碍
{
return;//函数结束
}
}
//实现让图形向下移动一个位置
for(i = 0; i < 4; i++)
{
shape[i].y++;
}
}
//打印动态图形
void showDynamicShape()
{
int i;
for(i = 0; i < 4; i++)
{
gotoxy(shape[i].x*2,shape[i].y);
printf("■");
}
}
//画动态图形
void drawDynamicShape()
{
shape[0].x = 5;
shape[0].y = 0;
shape[1].x = 6;
shape[1].y = 0;
shape[2].x = 5;
shape[2].y = 1;
shape[3].x = 6;
shape[3].y = 1;
}
//初始化静态背景边框
void initMap()
{
int i,j;
hideCursor();//隐藏光标
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(j == 0 || j == 11 || i == 20)
map[i][j] = 1;
else
map[i][j] = 0;
}
}
}
//打印静态背景图
void showStaticMap()
{
int i,j;
gotoxy(0,0);//每次打印边框前,将光标移动到坐标原点
for(i = 0; i < 21; i++)
{
for(j = 0; j < 12; j++)
{
if(map[i][j] == 0) //打印空格
{
printf(" ");//两个空格,是因一个星星的宽度占两个位置
}
else if(map[i][j] == 1)//打印边框
{
printf("★");
}
else if(map[i][j] == 2)//打印图形
{
printf("■");
}
}
printf("\n");
}
}
//控制光标位置
//隐藏光标
五、添加按键处理、控制左右下移动
5.1 添加按键处理、控制左右下移动
加上头文件conio.h ,在主函数中 if 条件判断是否有按键产生if(_kbhit()),在判断是哪一个按键,根据按键设定去执行相应的函数;左右移动是列数的移动,在移动前需要判断是否为0,如果不为0则无法移动,提前结束控制左右移动函数。
5.2 随机产生不同图形
添加time.h函数,srand(time(NULL))初始化随机种子,在画动态图形的函数中使用rand()生成一个随机数,使用switch()函数,根据随机数判断条件分支,画出相应图形
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdlib.h>
struct coord
{
int x;//x坐标
int y;//y坐标
};
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
void gotoxy(int x,int y);//控制光标的位置
void hideCursor();//隐藏光标
void drawDynamicShape();//画动态图形
void showDynamicShape();//打印动态图形
void moveDown();//向下移动
void addStaticMap();//添加到静态背景图中
void moveLeft();//向左移动
void moveRight();//向右移动
//全局变量
int currentShape;//用来保存当前图形的编号
int map[21][12];//保存静态背景图
struct coord shape[4];//保存了图形的四个坐标点
int main()
{
int i;
char input;//用来保存输入的按键
srand(time(NULL));//初始化随机种子
initMap();//初始化边框
drawDynamicShape();//画动态图形,对四个坐标点赋值
while(1)
{
showStaticMap();//打印静态图
showDynamicShape();//打印动态图形
moveDown();//向下移动
for(i = 0; i < 20; i++)
{
if(_kbhit())//检测是否有按键产生
{
input = _getch();
if(input == 'a')
{
/*printf("向左移动");*/
moveLeft();
input = 0;
}
else if(input == 'd')
{
/*printf("向右移动");*/
moveRight();
input = 0;
}
else if(input == 'w')
{
/*printf("变形");*/
//changeShape();
input = 0;
}
else if(input == 's')
{
/*printf("向下移动");*/
moveDown();
input = 0;
}
}
Sleep(50);
}
// Sleep(1000);//延时1000毫秒
}
getchar();
return 0;
}
//向左移动
void moveLeft()
{
int i;
//先要进行条件判断,判断是否能够向左移动
for(i = 0; i < 4; i++)
{
if(map[shape[i].y][shape[i].x-1] != 0)//碰到障碍物或边框
{
return;//结束函数
}
}
//向左移动
for(i = 0; i < 4; i++)
{
shape[i].x--;
}
}
//向右移动
void moveRight()
{
int i;
//先要进行条件判断,判断是否能够向右移动
for(i = 0; i < 4; i++)
{
if(map[shape[i].y][shape[i].x+1] != 0)//碰到障碍物或边框
{
return;//结束函数
}
}
//向右移动
for(i = 0; i < 4; i++)
{
shape[i].x++;
}
}
//将动态图形添加到静态背景图中
void addStaticMap()
{
int i;
for(i = 0; i < 4; i++)
{
map[shape[i].y][shape[i].x] = 2;
}
}
//向下移动
void moveDown()
{
int i;
//先判断能否向下移动
for(i = 0; i < 4; i++)
{//把四个坐标点,当做二维数组的行和列的下标
//x --->列
//y --->行
if(map[shape[i].y+1][shape[i].x] != 0)//y+1判断下一个位置是不是碰到障碍
{
//将动态图形添加到静态背景图中
addStaticMap();
//再次生成一个新的图形,再画一个图形
drawDynamicShape();
return;//函数结束,说明落到了最底下
}
}
//实现让图形向下移动一个位置
for(i = 0; i < 4; i++)
{
shape[i].y++;
}
}
//打印动态图形
void showDynamicShape()
{
int i;
for(i = 0; i < 4; i++)
{
gotoxy(shape[i].x*2,shape[i].y);
printf("■");
}
}
//画动态图形
void drawDynamicShape()
{
currentShape = rand()%3;//生成一个随机图形
switch(currentShape)
{
case 0:
shape[0].x = 5;//田字格
shape[0].y = 0;
shape[1].x = 6;
shape[1].y = 0;
shape[2].x = 5;
shape[2].y = 1;
shape[3].x = 6;
shape[3].y = 1;
break;
case 1:
shape[0].x = 4;//横条
shape[0].y = 0;
shape[1].x = 5;
shape[1].y = 0;
shape[2].x = 6;
shape[2].y = 0;
shape[3].x = 7;
shape[3].y = 0;
break;
case 2:
shape[0].x = 5;//竖条
shape[0].y = 0;
shape[1].x = 5;
shape[1].y = 1;
shape[2].x = 5;
shape[2].y = 2;
shape[3].x = 5;
shape[3].y = 3;
break;
}
}
六、消行、增加分数和难度
6.1 消行、增加分数
判断第 n 行是不是满行,是满行返回1,不是返回0,如果满行则调用清除单行满行函数,使用上一行覆盖掉当前的单行满行,同时再进行一次判断,避免出现连续的两个满行有bug
6.2 增加游戏难度水平
定义3个全局变量,分别进行初始化,游戏分数为0 难度水平为1 下降速度为20;if 条件判断分数、难度水平,根据当前分数和难度水平进行下降速度的调控;在消除单行函数中没消除一行就加多少分,由自己设定
#include <stdio.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
#include <stdlib.h>
struct coord
{
int x;//x坐标
int y;//y坐标
};
void initMap();//初始化静态背景边框
void showStaticMap();//打印静态背景图
void gotoxy(int x,int y);//控制光标的位置
void hideCursor();//隐藏光标
void drawDynamicShape();//画动态图形
void showDynamicShape();//打印动态图形
void moveDown();//向下移动
void addStaticMap();//添加到静态背景图中
void moveLeft();//向左移动
void moveRight();//向右移动
void clearFullLine();//清除满行
int isFullOneLine(int line);//判断line行是不是满行
void clearOneLine(int line);//清除当前的line满行
void addLevel();//增加游戏难度水平
//全局变量
int score = 0;//游戏分数
int level = 1;//游戏难度水平
int speed = 20;//用来控制下落速度
int currentShape;//用来保存当前图形的编号
int map[21][12];//保存静态背景图
struct coord shape[4];//保存了图形的四个坐标点
int main()
{
int i;
char input;//用来保存输入的按键
srand(time(NULL));//初始化随机种子
initMap();//初始化边框
drawDynamicShape();//画动态图形,对四个坐标点赋值
while(1)
{
showStaticMap();//打印静态图
showDynamicShape();//打印动态图形
moveDown();//向下移动
for(i = 0; i < speed; i++)
{
if(_kbhit())//检测是否有按键产生
{
input = _getch();
if(input == 'a')
{
/*printf("向左移动");*/
moveLeft();
input = 0;
}
else if(input == 'd')
{
/*printf("向右移动");*/
moveRight();
input = 0;
}
else if(input == 'w')
{
/*printf("变形");*/
//changeShape();
input = 0;
}
else if(input == 's')
{
/*printf("向下移动");*/
moveDown();
input = 0;
}
}
Sleep(50);
}
}
getchar();
return 0;
}
//增加游戏难度水平的函数
void addLevel()
{
if(score >= 500 && level == 1)
{
speed -= 5;
level = 2;
}
else if(score >= 2000 && level == 2)
{
speed -= 5;
level = 3;
}
else if(score >= 5000 && level == 3)
{
speed -= 5;
level = 4;
}
}
//判断第line行是不是满行,是满行返回1,不是返回0
int isFullOneLine(int line)
{
int j;
for(j = 1; j <= 10; j++)
{
if(map[line][j] == 0)//说明line不是满行
return 0;//0代表不是满行
}
//程序如果能执行到这,说明没有执行过return 0
return 1;//代表是满行
}
//清除单行满行
void clearOneLine(int line)
{
int i,j;
for(i = line; i > 0; i--)
{
for(j = 1; j <= 10; j++)
{
map[i][j] = map[i-1][j];
}
}
}
//消除满行
void clearFullLine()
{
int i;
for(i = 19; i > 0; i--)
{
//1.判断每一行i是不是满行
if(isFullOneLine(i))//返回值是1,说明是满行 1代表真
{
//2.消除当前的满行i
clearOneLine(i);
score += 100;
//3.增加游戏难度水平
addLevel();
i++;//避免出现连续的两个满行有bug
}
}
}
七、变化图形和游戏结束判断
7.1 图形变形功能
先确定图形是什么类型的图形,在变形前,先判断是否碰撞,除了中心点以外的三对坐标点是否碰撞,如果碰撞则无法变形 ;以中心点为坐标旋转90°后的坐标表示变形后的坐标
7.2 游戏结束判断功能
判断第0行是否为满,如果为满调用消行函数,如果第0行不为空则游戏结束,将难度等级和分数显示出来
八、项目过程的问题
8.1 问题一:坐标问题
map[21][12] 我们建立的坐标系x表示列数 y表示行数 ;因为图形 "■"占用两个字符位置所以要*2,在动态图形向下移动时,只要y变化就可以了,y才是行数
8.2 问题二:碰撞判断问题
在变形、左右移动、向下移动中都需要进行碰撞判断,碰撞检测函数int center :代表的是中心点,在结构体数组中的下标;三对x y,代表的除了中心点以外,其他点的变化值,如果碰撞返回值是1,不碰撞返回值0
总结
这里对文章进行总结:按照逻辑思维进行操作,步骤如下:
1、打印静态背景边框
先定义全局二维数组,将第0列11列和第20行赋值为1,其余赋值为0,遍历二维数组,将为1的打印星星,为0的打印两个空格,封装成初始化背景边框函数、打印静态背景边框函数
2、画一个动态图形,显示在顶部
全局定义一个结构体保存xy坐标点,全局定义一个结构体数组,保存动态图形的4个指标点,将动态图形打印封装成函数来显示动态图形,同时调用gotoxy函数(打印静态背景边框)和光标隐藏函数(初始化静态边框)
3、控制动态图形下落、动态图形添加到静态背景
图形下落,是行数的变化,即y++ ;添加静态背景图时,在下落前先判断,下一行是否为0,如果不为0,则停止下落,同时将结构体的4个坐标点赋值为2(非0非1即可),调用打印静态背景边框函数中添加一个条件,以此打印被添加到静态背景边框的动态图形。
4、产生新的动态图形并添加按键处理
在图形向下移动判断下一行不为0时,调用画动态图形函数,结束下落; 控制动态图形的向左、向右、向下移动,根据自己设定的按键,判断哪一个按键被触发,if条件去执行相应函数,以此控制动态图形的移动
5、消行、增加分数和难度水平
判断当前行是否满行,如果满行这清空当前行,同时在进行一次判断,防止bug两行都满行,但是只清除一行的情况;全局定义分数、难度等级和下降速度,根据消除一行添加多少分数,根据分数和难度等级分成不同的下降速度,以此来控制下降速度的快慢
6、图形变换和游戏结束判断功能
图形变化先先进行是否碰撞,除中心点外的其他3个坐标点在变化后是否会碰到左右背景边框、以及添加的静态背景图,如果不为0 即没有碰撞则可以变形,否则结束变形函数;判断第0行是否为空,如果不为空为满,这调用消行,如果不为空也不为满,这结束游戏。