⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 russianblock.c

📁 在linux系统下用ncurse写的俄罗斯方块
💻 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 + -