📄 russianblock.c
字号:
#include <curses.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <pthread.h>
#include <stdio.h>
//定义游戏窗口的属性
#define GAMELEFT 10
#define GAMEWIDTH 12
#define GAMETOP 3
#define GAMEHEIGHT 19
//定义显示下一个方块的窗口属性
#define NEXTLEFT 50
#define NEXTWIDTH 8
#define NEXTTOP 4
#define NEXTHEIGHT 8
//定义显示分数窗口的窗口属性
#define SCORELEFT 50
#define SCOREWIDTH 8
#define SCORETOP 14
#define SCOREHEIGHT 8
//帮助和得分以及下一个方块窗口的颜色对编号
#define HELP_ATTR 8
#define TIP_ATTR 9
#define GAME_ATTR 10
#define SCORE_ATTR 11
#define NEXT_ATTR 12
#define DOWN 0 //下
#define LEFT 1 //左
#define RIGHT 2 //右
#define UP 3 // 旋转
#define MINSPEED 0
#define ESCAPE 27
#define FIRST 100
#define LEVEL 10
int speed=0; //记录游戏的速度
int score=0; //记录分数的值
int xPos,yPos;
int type;
int x[3],y[3];
int down_speed;
int is_new_game;
int END_pressed;
int blockcolor;
//下述变量为下一个掉落方块的信息
int nextxPos,nextyPos;
int nextx[3],nexty[3];
int nexttype;
int nextblockcolor;
//选取一个基准点,
int blockx[][3]={ {-1,1,2},{-1,-1,0},{-1,1,1},{-1,-1,1},{-1,0,1},{-1,0,1},{-1,0,1}};
int blocky[][3]={ { 0,0,0},{ 0, 1,1},{ 0,0,1},{ 0, 1,0},{ 0,1,0},{ 0,1,1},{ 1,1,0}};
int GameSpace[GAMEHEIGHT][GAMEWIDTH];
int reach_bottom;//是否到达底部的变量
int game_over;//判断游戏是否结束
void initial();
void hello();
void game_start();
void show_win();
void show_tip();
void generate();
void down();
int clearrow();
void *down_one_line(void *is_end_pressed);
int isCollide(int,int,int x[],int y[]);
void addto(int ,int ,int x[],int y[],int );
void Rotate(int x[],int y[],int);
void Move(int);
void drawUnit(int ,int ,int ,char *);
void drawBlock(char* );
void drawGame(char*);
void new_game();
void show_score();
void show_next();
void quit_game();
void getNextBlock();
int main()
{
int key;
int temp;
pthread_t thread;
initial();
hello();
game_start();
while(1)
{
if(key != KEY_HOME)
{
show_tip(" Please press \"HOME\" to start the game, \"ESC\" to quit.", TIP_ATTR);
while((key=getch())!=KEY_HOME && key!=ESCAPE) ;
if(key ==ESCAPE) quit_game();
}
show_tip(" ", 0);
new_game();
pthread_create(&thread, NULL, down_one_line, (void *)&END_pressed);
do
{
getNextBlock();
is_new_game=0;
show_next();
if(isCollide(xPos,yPos,x,y))
{
game_over=1;
show_tip(" GAME OVER! Press \"HOME\" to start new game, \"ESC\" to quit.", TIP_ATTR);
}
reach_bottom =0;
while(!reach_bottom)
{
timeout(0);
key = getch();
switch(key)
{
case ESCAPE:
quit_game();
break;
case KEY_HOME:
new_game();
reach_bottom=1;
break;
case KEY_END:
show_tip(" PAUSE! Press \"END\" to continue.", TIP_ATTR);
END_pressed = 1;
while((key=getch())!=KEY_END) ;
END_pressed = 0;
show_tip(" ",0);
break;
case KEY_LEFT:
Move(LEFT);
break;
case KEY_RIGHT:
Move(RIGHT);
break;
case KEY_UP:
Move(UP);
break;
case KEY_DOWN:
Move(DOWN);
reach_bottom = 1;
break;
}
}
if(is_new_game ==0)
{ addto(xPos,yPos,x,y,blockcolor);
while((temp=clearrow())>0)
{
score+=temp;
show_score();
down_speed=score/20;
}
}
} while(game_over ==0) ;
show_tip(" GAME OVER! Press \"HOME\" to start new game, \"ESC\" to quit.", TIP_ATTR);
while((key=getch())!=KEY_HOME && key!=ESCAPE) ;
pthread_join(thread, NULL);
if(key == ESCAPE) quit_game();
}
return 0;
}
void initial()
{
initscr();
raw();
curs_set(0);//隐藏光标
nonl();
noecho();
intrflush(stdscr,FALSE);
keypad(stdscr,TRUE);
if(has_colors())
{
if(start_color() == ERR)
{
perror("start_color");
exit(EXIT_FAILURE);
}
}
//初始化在游戏中可能会用到的颜色对
init_pair(1, COLOR_BLACK, COLOR_BLACK);
init_pair(2, COLOR_RED, COLOR_RED);
init_pair(3, COLOR_GREEN, COLOR_GREEN);
init_pair(4, COLOR_YELLOW, COLOR_YELLOW);
init_pair(5, COLOR_BLUE, COLOR_BLUE);
init_pair(6, COLOR_MAGENTA, COLOR_MAGENTA);
init_pair(7, COLOR_CYAN, COLOR_CYAN);
init_pair(HELP_ATTR, COLOR_BLUE, COLOR_WHITE);
init_pair(TIP_ATTR, COLOR_RED, COLOR_WHITE);
init_pair(GAME_ATTR, COLOR_BLACK, COLOR_WHITE);
init_pair(SCORE_ATTR, COLOR_WHITE, COLOR_BLUE);
init_pair(NEXT_ATTR, COLOR_MAGENTA, COLOR_WHITE);
srand(time(0));}
//恢复设置并退出游戏
void quit_game()
{
curs_set(1); //恢复光标
clear();
echo();
refresh();
if(endwin() == ERR)
{ perror("endwin");
exit(EXIT_FAILURE);}
exit(EXIT_SUCCESS);
}
//欢迎界面
void hello()
{
int ymax, xmax;
getmaxyx(stdscr, ymax, xmax);
clear();
mvaddstr(ymax/4 , xmax/4, "******************************");
mvaddstr(ymax/4+1, xmax/4, "* *");
mvaddstr(ymax/4+2, xmax/4, "* Welcom to *");
mvaddstr(ymax/4+3, xmax/4, "* Game Russian Brick *");
mvaddstr(ymax/4+4, xmax/4, "* Press any key to play... *");
mvaddstr(ymax/4+5, xmax/4, "* *");
mvaddstr(ymax/4+6, xmax/4, "******************************");
refresh();
getch();
}
//绘制游戏进行时的窗口
void game_start()
{
int i;
clear();
attron(COLOR_PAIR(HELP_ATTR));
for(i=0;i<=79;i++)mvaddch(0,i,' ');
mvaddstr(0,23,"Russian Block");
attroff(COLOR_PAIR(HELP_ATTR));
attron(COLOR_PAIR(TIP_ATTR));
for(i=0;i<=79;i++)mvaddch(23,i,' ');
mvaddstr(24,0,"Press Home to restart,End to pause,Esc to exit");
attroff(COLOR_PAIR(TIP_ATTR));
show_win(GAMELEFT-1, GAMETOP-1,GAMEWIDTH+1,GAMEHEIGHT+2, GAME_ATTR);
show_win(SCORELEFT, SCORETOP, SCOREWIDTH, SCOREHEIGHT, SCORE_ATTR);
show_win(NEXTLEFT-1, NEXTTOP-1, NEXTWIDTH+1, NEXTHEIGHT+2, NEXT_ATTR);
attron(COLOR_PAIR(SCORE_ATTR));
mvaddstr(SCORETOP+1,SCORELEFT+2," High Score:");
mvaddstr(SCORETOP+3,SCORELEFT+2," Speed:");
mvaddstr(SCORETOP+5,SCORELEFT+2," Score:");
attroff(COLOR_PAIR(SCORE_ATTR));
attron(COLOR_PAIR(NEXT_ATTR));
mvaddstr(NEXTTOP+1,NEXTLEFT+2," Next Brick:");
attroff(COLOR_PAIR(NEXT_ATTR));
refresh();
}
//用给定的属性来绘制特定窗口
void show_win(int left,int top,int width,int height, int attr)
{
int i,j;
attron(COLOR_PAIR(attr));
for(i=left; i<left+2*width;i++)
{
mvaddch(top, i, '-');
mvaddch(top+height-1, i, '-');
}
for(i = top+1; i < top+height-1; i++)
{
mvaddch(i, left, '|');
mvaddch(i, left+2*width-1, '|');
}
for(i = left+1; i < left+2*width-1; i++)
for(j= top+1; j < top+height-1; j++)
mvaddch(j, i, ' ');
attroff(COLOR_PAIR(attr));
refresh();
}
//显示提示信息
void show_tip(char *msg, int attr)
{
int i;
attron(COLOR_PAIR(attr));
for(i=0;i<79;i++)mvaddch(23, i, ' ');
mvaddstr(23, 0, msg);
attroff(COLOR_PAIR(attr));
refresh();
}
//实现定时自动下落一行的线程函数
void *down_one_line(void *is_end_pressed)
{
int i,j;
int count=0;
do
{
usleep((FIRST - down_speed*LEVEL)*1000);
if(*((unsigned int *)is_end_pressed) ==1)continue;
if(!reach_bottom)
{
attron(COLOR_PAIR(GAME_ATTR));
for(i=GAMELEFT;i<GAMELEFT+2*GAMEWIDTH;i++)
for(j=GAMETOP;j<GAMETOP+GAMEHEIGHT;j++)
mvaddch(j,i,' ');
attroff(COLOR_PAIR(GAME_ATTR));
if(++count>4)
{ down();count=0;}
drawBlock(" ");
drawGame(" ");
}
} while(game_over ==0) ;
pthread_exit(NULL);
}
//判断是否冲突
int isCollide(int xPos,int yPos,int x[3],int y[3])
{
int i;
int x1[4];
int y1[4];
x1[0]=xPos;y1[0]=yPos;
for(i=0;i<3;i++)
{
x1[i+1]=xPos+x[i];
y1[i+1]=yPos+y[i];}
for(i=0;i<4;i++)
{
if(x1[i]<0||x1[i]>=GAMEWIDTH)return 1;
if(y1[i]<0||y1[i]>=GAMEHEIGHT)return 1;
if(GameSpace[y1[i]][x1[i]])return 1;
}
return 0;
}
// 当一个方块下降到底部时,将其添加到游戏窗口中
void addto(int xPos,int yPos,int x[3],int y[3],int attr)
{
int i;
int x1[4];
int y1[4];
x1[0]=xPos;y1[0]=yPos;
for(i=0;i<3;i++)
{
x1[i+1]=xPos+x[i];
y1[i+1]=yPos+y[i];
}
for(i=0;i<4;i++)GameSpace[y1[i]][x1[i]]=attr;
}
//实现方块的向左,向右,翻转,快速向下的移动
void Move(int direction)
{
int temp;
int x1[3];
int y1[3],i;
switch(direction)
{
case LEFT:
if(!isCollide(xPos-1,yPos,x,y))
xPos--;
break;
case RIGHT:
if(!isCollide(xPos+1,yPos,x,y))xPos++;
break;
case UP:
for(i=0;i<3;i++){x1[i]=x[i];y1[i]=y[i];}
Rotate(x1,y1,1);
if(!isCollide(xPos,yPos,x1,y1))Rotate(x,y,1);
break;
case DOWN:
temp=yPos;
while(!isCollide(xPos,++temp,x,y));
temp--;
if(temp>yPos)yPos=temp;
break;
}
}
//实现方块的翻转(顺时钟和逆时钟)
void Rotate(int x[3],int y[3],int flag)
{
int temp;
int i;
if(type==1)return;
for(i=0;i<3;i++)
{
if(flag=1)
{ temp=x[i];
x[i]=y[i];
y[i]=-temp;
}
else
{
temp=x[i];
x[i]=-y[i];
y[i]=temp;
} }
}
//清除满行
int clearrow()
{
int i=GAMEHEIGHT-1;
int j,k,s,t;
int count=0;
while(i>=0)
{
t=0;
for(j=0;j<GAMEWIDTH;j++)
if(GameSpace[i][j]!=0)t++;
if(t==0)break;
if(t==GAMEWIDTH)
{
count++;
for(j=i;j>0;j--)
for(k=0;k<GAMEWIDTH;k++)
GameSpace[j][k]=GameSpace[j-1][k];
for(s=0;s<GAMEWIDTH;s++)
GameSpace[0][s]=0;
}
else i--;
}
return count;
}
//在指定的单位位置上用特定颜色画特定字符串
void drawUnit(int x,int y,int attr,char* s)
{
if(y<0)return ;
wattron(stdscr,COLOR_PAIR(attr));
mvwaddstr(stdscr,GAMETOP+y,GAMELEFT+2*x,s);
wattroff(stdscr,COLOR_PAIR(attr));
}
//在游戏窗口中绘制下落的方块
void drawBlock(char* s)
{
int i;
drawUnit(xPos,yPos,blockcolor,s);
for(i=0;i<3;i++)
drawUnit(xPos+x[i],yPos+y[i],blockcolor,s);
wrefresh(stdscr);
}
//绘制游戏窗口中下方已经不动的小方格
void drawGame(char* s)
{
int i,j;
for(i=0;i<GAMEHEIGHT;i++)
for(j=0;j<GAMEWIDTH;j++)
if(GameSpace[i][j])
drawUnit(j,i,GameSpace[i][j],s);
wrefresh(stdscr);
}
//控制游戏中的方块每次下落一行
void down()
{
if(!isCollide(xPos,yPos+1,x,y))yPos++;
else
{
reach_bottom=1;
}
}
//随机产生不同颜色的方块
void generate()
{
int i;
nextxPos=6;
nextyPos=0;
nexttype=rand()%7;
nextblockcolor=rand()%6+2;
for(i=0;i<3;i++)
{
nextx[i]=blockx[nexttype][i];
nexty[i]=blocky[nexttype][i]; }
reach_bottom=0;
}
//开始新游戏
void new_game()
{
int i,j; score = 0;
down_speed = MINSPEED;
game_over = 0;
for(i=0;i<GAMEHEIGHT;i++)
for(j=0;j<GAMEWIDTH;j++)
GameSpace[i][j]=0;
drawGame(" ");
nextxPos=6;
nextyPos=0;
nexttype=2;
nextblockcolor=3;
for(i=0;i<3;i++)
{
nextx[i]=blockx[nexttype][i];
nexty[i]=blocky[nexttype][i]; }
is_new_game=1;
show_score();
}
//显示得分的窗口
void show_score()
{
attron(COLOR_PAIR(SCORE_ATTR));
mvprintw(SCORETOP+6, SCORELEFT+3, "%-12ld",score);
mvprintw(SCORETOP+4, SCORELEFT+3, "%-2d",down_speed);
attroff(COLOR_PAIR(SCORE_ATTR));
refresh();
}
void getNextBlock()
{ int i,j;
xPos=nextxPos;
yPos=nextyPos;
for(i=0;i<3;i++)
{ x[i]=nextx[i];
y[i]=nexty[i]; }
type=nexttype;
blockcolor=nextblockcolor;
}
//在NEXT窗口中显示下一个方块
void show_next()
{
int i,j;
generate();
attron(COLOR_PAIR(GAME_ATTR));
for(i=0;i<NEXTHEIGHT;i++)
for(j=0;j<NEXTWIDTH;j++)
mvaddstr(NEXTTOP+i,NEXTLEFT+2*j," ");
attroff(COLOR_PAIR(GAME_ATTR));
attron(COLOR_PAIR(nextblockcolor));
mvaddstr(NEXTTOP+4,NEXTLEFT+2*4," ");
for(i=0;i<3;i++)
{ mvaddstr(NEXTTOP+4+nexty[i],NEXTLEFT+2*(4+nextx[i])," "); }
attroff(COLOR_PAIR(nextblockcolor));
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -