首页 > 编程 > C++ > 正文

C++制作俄罗斯方块

2020-05-23 14:05:01
字体:
来源:转载
供稿:网友
俄罗斯方块写过好几次了,每次的感觉都不一样,都有新的收获。就像达芬奇画鸡蛋一样,虽然都是画同样的鸡蛋,但是每次都有不同的收获。 
 

缘起:

  在玩Codeblocks自带的俄罗斯方块时觉得不错,然而有时间限制。所以想自己再写一个。

程序效果:

C++,俄罗斯方块

主要内容:

  程序中有一个board数组,其中有要显示的部分,也有不显示的部分,不显示的部分都存储1。

  如下图:

C++,俄罗斯方块

  shape采用4*4数组(shape)保存。如:

    0 0 0 0
    0 1 0 0 
    1 1 1 0
    0 0 0 0

  另外用变量row和column保存shape数组左上角在board中的位置。

  每次下落或左右移动,先对row和column做出改变,然后检测当前row和column下,shape是否重合了为1的格子,如果有重合,就说明shape出界了或者到达下落最低点,则要恢复row和column值。另外,如果是下落,还要将shape放在board上,并产生新的shape。

  旋转时,先对shape数组进行旋转操作,然后检测重合,如果有重合,则反向旋转回来。

代码:

#if defined(UNICODE) && !defined(_UNICODE)#define _UNICODE#elif defined(_UNICODE) && !defined(UNICODE)#define UNICODE#endif#include <tchar.h>#include <windows.h>#include <pthread.h>#include <stdio.h>#include <time.h>/*-----------------宏定义--------------------------------------------------------*/#define WIDTH 180#define HEIGHT 400#define LONG_SLEEP 300#define BKCOLOR RGB(238,238,238)//背景色/*-----------------变量----------------------------------------------------------*/static int shapes[7][4][4];//存储7个形状static int high_score[4]= {0,0,0,0};//前三个元素存储最高分,最后一个元素存储此次得分static int **shape;//当前形状static int **board;static int M=15;//显示的列数static int N=30;//显示的行数static int MM=M+8;//board的列数static int NN=N+4;//board的行数static int LEFT=4;//显示的最左一列static int RIGHT=LEFT+M-1;//显示的最右一列static int TOP=0;//显示的最上一列static int BOTTOM=N-1;//显示的最下一列static int score=0;static int row=0;//形状所在行static int column=MM/2;//形状坐在列static bool is_pause=false;static HBRUSH grey_brush =CreateSolidBrush (RGB(210,210,210));static HBRUSH white_brush =CreateSolidBrush (RGB(130,130,130));static HBRUSH bk_brush =CreateSolidBrush (BKCOLOR);static HPEN hPen = CreatePen(PS_SOLID,1,RGB(147,155,166));static int lattices_top=40;//上面留白static int lattices_left=20;//左侧留白static int width=WIDTH/M;//每个格子的宽度static int height=(HEIGHT-lattices_top)/N;//每个格子的高度/*-----------------函数-----------------------------------------------------------*/void add_score() ;bool check_is_lose() ;void clear_up() ;//消除没有空格子的行void* down_thread_function(void * args) ;//形状下落进程要执行的函数void exit_game(HWND hwnd) ;void give_new_shape() ;//随机生成一个新形状int handle_key(HWND hwnd,WPARAM wParam) ;int init_down_thread(HWND hwnd) ;//初始化形状下落进程int init_game(HWND hwnd) ;//初始化游戏程序void init_play() ;//初始化游戏数据bool is_legel() ;//检测形状在当前位置是否合法(即是否重合了非空的格子)int load_scores(int* a) ;//读取游戏最高分数据int load_shape() ;//从文件中加载7个形状void lose_game(HWND hwnd) ;int move_down(HWND hwnd) ;//形状下落int move_lr(HWND hwnd,int lr) ;//形状左右移动void paint_lattice(HDC hdc,int x,int y,int color) ;//显示一个格子void paint_UI(HDC hdc) ;//画界面void reset_rc() ;void rerotate_matrix(int mn) ;//顺时针旋转一个行列数为mn的方阵void rotate_matrix(int mn) ;//逆时针旋转一个行列数为mn的方阵int rotate_shape(HWND hwnd) ;//旋转当前形状并更新界面bool save_score(HWND hwnd) ;//保存最高分数据void shape_to_ground() ;//当前形状落地之后,更新boardbool sort_scores(int* a) ;//对最高分和此次得分排序,若创造新纪录则返回truevoid update_UI(HWND hwnd) ;//更新界面,仅更新Rect区域(形状所在的那几行)内void update_UI_all(HWND hwnd) ;//更新界面,更新整个界面int write_scores(int* a) ;//写最高分数据/* Declare Windows procedure */LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);/* Make the class name into a global variable */TCHAR szClassName[ ] = _T("Tris");int WINAPI WinMain (HINSTANCE hThisInstance,          HINSTANCE hPrevInstance,          LPSTR lpszArgument,          int nCmdShow) {  HWND hwnd;        /* This is the handle for our window */  MSG messages;      /* Here messages to the application are saved */  WNDCLASSEX wincl;    /* Data structure for the windowclass */  /* The Window structure */  wincl.hInstance = hThisInstance;  wincl.lpszClassName = szClassName;  wincl.lpfnWndProc = WindowProcedure;   /* This function is called by windows */  wincl.style = CS_DBLCLKS;         /* Catch double-clicks */  wincl.cbSize = sizeof (WNDCLASSEX);  /* Use default icon and mouse-pointer */  wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);  wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);  wincl.hCursor = LoadCursor (NULL, IDC_ARROW);  wincl.lpszMenuName = NULL;         /* No menu */  wincl.cbClsExtra = 0;           /* No extra bytes after the window class */  wincl.cbWndExtra = 0;           /* structure or the window instance */  /* Use Windows's default colour as the background of the window */  wincl.hbrBackground =bk_brush;  /* Register the window class, and if it fails quit the program */  if (!RegisterClassEx (&wincl))    return 0;  /* The class is registered, let's create the program*/  hwnd = CreateWindowEx (        0,          /* Extended possibilites for variation */        szClassName,     /* Classname */        _T("Tris"),    /* Title Text */        WS_OVERLAPPEDWINDOW, /* default window */        CW_USEDEFAULT,    /* Windows decides the position */        CW_USEDEFAULT,    /* where the window ends up on the screen */        WIDTH+200,         /* The programs width */        HEIGHT+70,         /* and height in pixels */        HWND_DESKTOP,    /* The window is a child-window to desktop */        NULL,        /* No menu */        hThisInstance,    /* Program Instance handler */        NULL         /* No Window Creation data */      );  /* Make the window visible on the screen */  ShowWindow (hwnd, nCmdShow);  /* Run the message loop. It will run until GetMessage() returns 0 */  while (GetMessage (&messages, NULL, 0, 0)) {    /* Translate virtual-key messages into character messages */    TranslateMessage(&messages);    /* Send message to WindowProcedure */    DispatchMessage(&messages);  }  /* The program return-value is 0 - The value that PostQuitMessage() gave */  return messages.wParam;}//从文件中加载7个形状int load_shape() {  FILE* f=fopen("shapes.txt","rb");  if(f==NULL) {    return -1;  }  for(int i=0; i<7; i++) {    for(int j=0; j<4; j++) {      for(int k=0; k<4; k++) {        if(fscanf(f,"%d",&shapes[i][j][k])!=1) {          return -1;        }      }    }  }  fclose(f);  return 0;}//随机生成一个新形状void give_new_shape() {  int shape_num=rand()%7;  for(int i=0; i<4; i++) {    for(int j=0; j<4; j++) {      shape[i][j]=shapes[shape_num][i][j];    }  }}void add_score() {  score+=100;}//消除没有空格子的行void clear_up() {  for(int i=row; i<=row+3; i++) {    if(i>BOTTOM)continue;    bool there_is_blank=false;    for(int j=LEFT; j<=RIGHT; j++) {      if(board[i][j]==0) {        there_is_blank=true;        break;      }    }    if(!there_is_blank) {      add_score();      for(int r=i; r>=1; r--) {        for(int c=LEFT; c<=RIGHT; c++) {          board[r][c]=board[r-1][c];        }      }    }  }}//检测形状在当前位置是否合法(即是否重合了非空的格子)bool is_legel() {  for(int i=0; i<4; i++) {    for(int j=0; j<4; j++) {      if(shape[i][j]==1&&board[row+i][column+j]==1) {        return false;      }    }  }  return true;}//逆时针旋转一个行列数为mn的方阵void rotate_matrix(int mn) {  int** a=shape;  int s=0;  for(int n=mn; n>=1; n-=2) {    for(int i=0; i<n-1; i++) {      int t=a[s+i][s];      a[s+i][s]=a[s][s+n-i-1];      a[s][s+n-i-1]=a[s+n-i-1][s+n-1];      a[s+n-i-1][s+n-1]=a[s+n-1][s+i];      a[s+n-1][s+i]=t;    }    s++;  }}//顺时针旋转一个行列数为mn的方阵void rerotate_matrix(int mn) {  int** a=shape;  int s=0;  for(int n=mn; n>=1; n-=2) {    for(int i=0; i<n-1; i++) {      int t=a[s+i][s];      a[s+i][s]=a[s+n-1][s+i];      a[s+n-1][s+i]=a[s+n-i-1][s+n-1];      a[s+n-i-1][s+n-1]=a[s][s+n-i-1];      a[s][s+n-i-1]=t;    }    s++;  }}//显示一个格子void paint_lattice(HDC hdc,int x,int y,int color) {  if(x<TOP||x>BOTTOM||y<LEFT||y>RIGHT) {    return ;  }  x-=TOP;  y-=LEFT;  int left=lattices_left+y*width;  int right=lattices_left+y*width+width;  int top=lattices_top+x*height;  int bottom=lattices_top+x*height+height;  MoveToEx (hdc,left,top, NULL) ;  LineTo (hdc,right,top) ;  MoveToEx (hdc,left,top, NULL) ;  LineTo (hdc,left,bottom) ;  MoveToEx (hdc,left,bottom, NULL) ;  LineTo (hdc,right,bottom) ;  MoveToEx (hdc,right,top, NULL) ;  LineTo (hdc,right,bottom) ;  SelectObject(hdc, grey_brush);  if(color==0) {    SelectObject(hdc, white_brush);  }  Rectangle(hdc,left,top,right,bottom);}//更新界面,仅更新Rect区域(形状所在的那几行)内void update_UI(HWND hwnd) {  static RECT rect;  rect.left=lattices_left;  rect.right=lattices_left+M*width+width;  rect.top=lattices_top+(row-1)*height;  rect.bottom=lattices_top+(row+4)*height;  InvalidateRect (hwnd,&rect, false) ;}//更新界面,更新整个界面void update_UI_all(HWND hwnd) {  InvalidateRect (hwnd,NULL, false) ;}//画界面void paint_UI(HDC hdc) {  SetBkColor(hdc,BKCOLOR);  SelectObject(hdc,hPen); //选用画笔  char score_str[20];  sprintf(score_str,"Score:%d",score);  TextOut(hdc,10,10,score_str,strlen(score_str));  sprintf(score_str,"Highest Scores:");  TextOut(hdc,WIDTH+50,50,score_str,strlen(score_str));  for(int i=0; i<3; i++) {    sprintf(score_str,"%d",high_score[i]);    TextOut(hdc,WIDTH+50,50+(i+1)*20,score_str,strlen(score_str));  }  for(int i=TOP; i<=BOTTOM; i++) {    for(int j=LEFT; j<=RIGHT; j++) {      paint_lattice(hdc,i,j,board[i][j]);    }  }  for(int i=0; i<4; i++) {    for(int j=0; j<4; j++) {      if(shape[i][j]==1)        paint_lattice(hdc,row+i,column+j,shape[i][j]);    }  }}//旋转当前形状并更新界面int rotate_shape(HWND hwnd) {  int mn=4;  rotate_matrix(mn);  if(!is_legel()) {    rerotate_matrix(mn);  }  update_UI(hwnd);}void reset_rc() {  row=0;  column=MM/2-2;}//读取游戏最高分数据int load_scores(int* a) {  FILE* f=fopen("scores.txt","r");  if(f==NULL)return -1;  fscanf(f,"%d%d%d",&a[0],&a[1],&a[2]);  return 0;}//初始化游戏数据void init_play() {  load_scores(high_score);  for(int i=0; i<NN; i++) {    for(int j=0; j<MM; j++) {      board[i][j]=0;    }  }  for(int i=0; i<N; i++) {    for(int j=0; j<LEFT; j++) {      board[i][j]=1;    }  }  for(int i=0; i<N; i++) {    for(int j=RIGHT+1; j<MM; j++) {      board[i][j]=1;    }  }  for(int i=BOTTOM+1; i<NN; i++) {    for(int j=0; j<MM; j++) {      board[i][j]=1;    }  }  reset_rc();  score=0;  give_new_shape();  is_pause=false;  return ;}bool check_is_lose() {  if(row==0)return true;  return false;}//对最高分和此次得分排序,若创造新纪录则返回truebool sort_scores(int* a) {  int temp=a[3];  for(int i=0; i<4; i++) {    for(int j=0; j<3; j++) {      if(a[j]<a[j+1]) {        int t=a[j];        a[j]=a[j+1];        a[j+1]=t;      }    }  }  if(temp>a[3])return true;  return false;}//写最高分数据int write_scores(int* a) {  FILE* f=fopen("scores.txt","w");  if(f==NULL)return -1;  fprintf(f,"%d/n%d/n%d/n",a[0],a[1],a[2]);  return 0;}//保存最高分数据bool save_score(HWND hwnd) {  high_score[3]=score;  bool made_record=sort_scores(high_score);  if(write_scores(high_score)!=0) {    MessageBox(hwnd,"Write file error.Program will exit.","Error",NULL);    DestroyWindow(hwnd);  }  return made_record;}void lose_game(HWND hwnd) {  if(is_pause)return ;  is_pause=true;  char message[200]="You lose the Game./n";  char title[50]="Game Over";  if(save_score(hwnd)) {    strcat(message,"You have made a new record./n");    char score_str[100];    sprintf(score_str,"The Highest Scores:/n%d/n%d/n%d/n",high_score[0],high_score[1],high_score[2]);    strcat(message,score_str);  }  strcat(message,"/nPlay again?/n");  if(MessageBox(hwnd,message,title,MB_YESNO)==IDYES) {    init_play();    update_UI_all(hwnd);  } else {    exit(0);  }}void exit_game(HWND hwnd) {  is_pause=true;  char message[200]="";  char title[50]="Exit";  if(save_score(hwnd)) {    strcat(message,"You have made a new record./n");    char score_str[100];    sprintf(score_str,"The Highest Scores:/n%d/n%d/n%d/n",high_score[0],high_score[1],high_score[2]);    strcat(message,score_str);    MessageBox(hwnd,message,title,NULL);  }  exit(0);}//当前形状落地之后,更新boardvoid shape_to_ground() {  for(int i=0; i<4; i++) {    for(int j=0; j<4; j++) {      board[row+i][column+j]=shape[i][j]==1?1:board[row+i][column+j];    }  }}//形状下落int move_down(HWND hwnd) {  row++;  if(!is_legel()) {    row--;    if(check_is_lose()) {      lose_game(hwnd);      return 0;    }    shape_to_ground();    clear_up();    update_UI_all(hwnd);    reset_rc();    give_new_shape();  }  update_UI(hwnd);}//进程参数结构体struct thread_arg {  HWND arg_hwnd;};//形状下落进程要执行的函数void* down_thread_function(void * args) {  thread_arg *arg=(thread_arg*)args;  HWND dhwnd=arg->arg_hwnd;  while(true) {    if(is_pause) {      Sleep(300);      continue;    }    move_down(dhwnd);    Sleep(LONG_SLEEP);  }}//初始化形状下落进程int init_down_thread(HWND hwnd) {  int ret;  pthread_t t;  thread_arg *argp=new thread_arg;  argp->arg_hwnd=hwnd;  ret=pthread_create(&t,NULL,down_thread_function,argp);  delete argp;  if(ret!=0) {    return -1;  }  return 0;}//初始化游戏程序int init_game(HWND hwnd) {  board=new int*[NN];  for(int i=0; i<NN; i++) {    board[i]=new int[MM];  }  shape=new int*[4];  for(int i=0; i<4; i++) {    shape[i]=new int[4];  }  srand(time(0));  if(load_shape()!=0) {    MessageBox(hwnd,"Read file error.Program will exit.","Error",NULL);    exit(-1);  }  init_play();  update_UI_all(hwnd);  if(init_down_thread(hwnd)!=0) {    MessageBox(hwnd,"Thread error.Program will exit.","Error",NULL);    exit(-1);  }  return 0;}//形状左右移动int move_lr(HWND hwnd,int lr) {  int temp=column;  if(lr==0)column--;  else {    column++;  }  if(!is_legel()) {    column=temp;  }  update_UI(hwnd);}int handle_key(HWND hwnd,WPARAM wParam) {  if(wParam==VK_ESCAPE) {//ESC退出    exit_game(hwnd);  }  if(wParam==VK_SPACE) {//空格暂停    is_pause=!is_pause;  }  if(is_pause==true) {    Sleep(300);    return 0;  }  if(wParam==VK_UP) {    rotate_shape(hwnd);  }  if(wParam==VK_DOWN) {    move_down(hwnd);  }  if(wParam==VK_LEFT) {    move_lr(hwnd,0);  }  if(wParam==VK_RIGHT) {    move_lr(hwnd,1);  }  return 0;}/* This function is called by the Windows function DispatchMessage() */HWND hwnd;LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {  static HDC hdc;  static HDC hdcBuffer;  static HBITMAP hBitMap;  static PAINTSTRUCT ps ;  switch (message) {        /* handle the messages */  case WM_CREATE:    init_game(hwnd);    break;  case WM_KEYDOWN:    handle_key(hwnd,wParam);    break;  case WM_DESTROY:    exit_game(hwnd);    PostQuitMessage (0);    /* send a WM_QUIT to the message queue */    break;  case WM_PAINT:    hdc = BeginPaint (hwnd, &ps) ;    paint_UI(hdc);    EndPaint (hwnd, &ps) ;    break;  default:           /* for messages that we don't deal with */    return DefWindowProc (hwnd, message, wParam, lParam);  }  return 0;}


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表