#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#define TTY_PATH "/dev/tty"
#define STTY_US "stty raw -echo -F "
#define STTY_DEF "stty -raw echo -F "
struct Point//坐标类型
{
int x;
int y;
};
struct Shap//图形类型
{
struct Point points[4];
};
//图形库
struct Shap shaps[19] = {
{{{0,0},{-1,0},{1,0},{2,0}}},//横条
{{{0,0},{0,-1},{0,1},{0,2}}},//竖条
{{{0,0},{-1,-1},{-1,0},{0,-1}}},//方块
{{{0,0},{0,-1},{0,-2},{1,0}}},//正L1
{{{0,0},{0,1},{1,0},{2,0}}},//正L2
{{{0,0},{-1,0},{0,1},{0,2}}},//正L3
{{{0,0},{0,-1},{-1,0},{-2,0}}},//正L4
{{{0,0},{-1,0},{0,-1},{0,-2}}},//反L1
{{{0,0},{0,-1},{1,0},{2,0}}},//反L2
{{{0,0},{1,0},{0,1},{0,2}}},//反L3
{{{0,0},{-1,0},{-2,0},{0,1}}},//反L4
{{{0,0},{-1,0},{1,0},{0,-1}}},//T1
{{{0,0},{0,1},{0,-1},{1,0}}},//T2
{{{0,0},{-1,0},{1,0},{0,1}}},//T3
{{{0,0},{-1,0},{0,-1},{0,1}}},//T4
{{{0,0},{1,0},{0,-1},{-1,-1}}},//正Z1
{{{0,0},{1,-1},{0,1},{1,0}}},//正Z2
{{{0,0},{1,-1},{-1,0},{0,-1}}},//反z1
{{{0,0},{-1,-1},{-1,0},{0,1}}}//反Z2
};
#define WIDTH 20
#define HEIGHT 30
#define CHANGE 'w'
#define RIGHT 'd'
#define LEFT 'a'
#define DOWN 's'
#define CTRL_C 3
struct Point position = {WIDTH/2, 2};//图形的坐标位置
struct Shap nowShap;//表示当前的图形
int nowShapIndex;//当前图形在图形库中的角标
int staticShapes[HEIGHT+2][WIDTH+2] = {
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
{0,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,1,1,1,0},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
};//保存下落后的静态图形 每个元素表示屏幕上的一个点 0该点没有图形 1该点有图形
int get_char(); //能实现非阻塞IO, 如果没有按下按键,程序继续往下走
void drowPoint(int x, int y);
void drowStar(int x, int y);
void drawFrame();
void userCtrl();
void createShap();
void drawShap();
void moveDown();
int collide(struct Shap shap);
void addShapToStatic();
void drawStaitcShapes();
void clearLines();
int main()
{
srand(time(0));//初始化随机种子 只初始化一次
system( STTY_US TTY_PATH );
createShap();//创建一个图形
while(1)
{
system("clear");
drawShap();
drawStaitcShapes();
drawFrame();
userCtrl();
moveDown();
fflush(stdout);
usleep(100000);//50毫秒 每秒20帧
}
return 0;
}
//创建图形
void createShap()
{
position.x = WIDTH/2;
position.y = 2;
//nowShapIndex = rand()%19;//随机一个图形的角标
nowShapIndex = 0;
nowShap = shaps[nowShapIndex];//随机一个图形
}
//自然下落
int moveDownSpeed = 0;
void moveDown()
{
if(++moveDownSpeed == 5)
{
//计算出假设移动后的图形
struct Shap shap = nowShap;
int i;
for(i = 0;i < 4;i++)
{
shap.points[i].x += position.x;
shap.points[i].y += position.y+1;
}
//如果没有碰撞,才向下移动
if(collide(shap)==0)
{
position.y++;
}
else//到底了
{
addShapToStatic();//将图形加入到静态
clearLines();
createShap();//创建新图形
}
moveDownSpeed = 0;
}
}
//变形
void changeShap()
{
int index = nowShapIndex;
switch(nowShapIndex)
{
case 0://横条
index++;
break;
case 1://竖条
index = 0;
break;
case 2://方块
break;
case 3://正L1
case 4:
case 5:
index++;
break;
case 6://正L4
index = 3;//变回正L1
break;
case 7://反L1
case 8:
case 9:
index++;
break;
case 10://反L4
index = 7;//变回反L1
break;
case 11://T 1
case 12:
case 13:
index++;
break;
case 14://T 4
index = 11;//变回T 1
break;
case 15://zz1
index = 16;
break;
case 16://zz2
index = 15;
break;
case 17://fz1
index = 18;
break;
case 18://fz2
index = 17;
break;
}
//假设变形
struct Shap shap = shaps[index];
int i;
for(i = 0;i < 4;i++)
{
shap.points[i].x += position.x;
shap.points[i].y += position.y;
}
//如果变形后不碰撞,才变形
if(collide(shap) == 0)
{
nowShapIndex = index;
nowShap = shaps[index];
}
}
//将图形加入到静态数组中
void addShapToStatic()
{
int i;//遍历图形中的4个点,找到staticShapes中的对应元素,置1
for(i = 0;i < 4;i++)
{
int x = nowShap.points[i].x+position.x;
int y = nowShap.points[i].y+position.y;
staticShapes[y][x] = 1;
}
}
//显示静态图形
void drawStaitcShapes()
{
int i, j;
for(i = 0;i < HEIGHT+2;i++)//外层循环遍历y轴
{
for(j = 0;j < WIDTH+2;j++)//内层循环遍历X轴
{
if(staticShapes[i][j] == 1)//这个点是有图形的
{
drowPoint(j, i);//j是x i是y
}
}
}
}
//绘制一个图形
void drawShap()
{
int i;
for(i = 0;i < 4;i++)
{
drowPoint(position.x+nowShap.points[i].x, position.y+nowShap.points[i].y);
}
}
//碰撞判定
//参数:判断的图形
//返回值 1 碰撞 0没有碰撞
int collide(struct Shap shap)
{
int i;
for(i = 0;i < 4;i++)
{
int x = shap.points[i].x;
int y = shap.points[i].y;
if(shap.points[i].x < 1 //左边
|| shap.points[i].x > WIDTH//右边
|| shap.points[i].y > HEIGHT//下边
|| staticShapes[y][x]==1 //
)
{
return 1;
}
}
return 0;
}
//判断一行是否满
//参数:行号
//返回值:1 满 0不满
int isLineFull(int line)
{
int i;
for(i = 1;i < WIDTH+1;i++)
{
if(staticShapes[line][i] == 0)
{
return 0;
}
}
return 1;
}
//行赋值
//参数1和参数2是两个行号 line2覆盖 line1
void lineCpy(int line1, int line2)
{
int i;
for(i = 1;i < WIDTH+1;i++)
{
staticShapes[line1][i] = staticShapes[line2][i];
}
}
//将整行置0
//参数:行号
void setLine(int line)
{
int i;
for(i = 1;i < WIDTH+1;i++)
{
staticShapes[line][i] = 0;
}
}
//消行
void clearLines()
{
int mark[HEIGHT+2] = {0};//存放标记的数组,因为一共HEIGHT+2行 0 和HEIGHT+1是边界
int i;
int count = 0;
//统计每一行应该移动的距离
for(i = HEIGHT;i > 1;i--)//从底行向上遍历
{
if(isLineFull(i) == 1)//找到了满行
{
mark[i] = -1;
count++;
}
else
{
mark[i] = count;
}
}
//移动
for(i = HEIGHT;i > 1;i--)
{
int len = mark[i];
if(mark[i] == -1)//这是要被消掉的行,不用挪动
{
continue;
}
if(len > 0)
{
lineCpy(i+len, i);//ii+len行被 i行覆盖
setLine(i);//挪一行就清一行
}
}
//清空后面的行 一共需要清理count行,行号从1开始
/*for(i = 0;i < count;i++)
{
setLine(i+1);
}*/
}
//绘制游戏边框
void drawFrame()
{
int i;
//最上面一行
for(i = 0;i < WIDTH+2;i++)
{
drowStar(i, 0);
drowStar(i, HEIGHT+1);
}
for(i = 0;i < HEIGHT+2;i++)
{
drowStar(0, i);
drowStar(WIDTH+1, i);
}
}
//用户输入并控制坐标
void userCtrl()
{
struct Shap shap = nowShap;
int i;
switch(get_char())
{
case CHANGE://变形
changeShap();
break;
case DOWN:
break;
case RIGHT:
for(i = 0;i < 4;i++)
{
shap.points[i].x += position.x+1;
shap.points[i].y += position.y;
}
if(collide(shap) == 0)
{
position.x++;
}
break;
case LEFT:
for(i = 0;i < 4;i++)
{
shap.points[i].x += position.x-1;
shap.points[i].y += position.y;
}
if(collide(shap) == 0)
{
position.x--;
}
break;
case CTRL_C:
system(STTY_DEF TTY_PATH);
exit(0);//结束程序
break;
}
}
void drowPoint(int x, int y)
{
printf("\033[%d;%dH", y+1, x*2+1);
printf("\033[1;36m■ \033[0m");
}
void drowStar(int x, int y)
{
printf("\033[%d;%dH", y+1, x*2+1);
printf("\033[1;36m* \033[0m");
}
int get_char() //能实现非阻塞IO, 如果没有按下按键,程序继续往下走
{
fd_set rfds;
struct timeval tv;
int ch = 0;
FD_ZERO(&rfds);
FD_SET(0, &rfds);
tv.tv_sec = 0;
tv.tv_usec = 10; //设置等待超时时间
//检测键盘是否有输入
if (select(1, &rfds, NULL, NULL, &tv) > 0)
{
ch = getchar();
}
return ch;
}
俄罗斯方块C语言版(linux下)
最新推荐文章于 2024-09-21 09:09:05 发布