zoukankan      html  css  js  c++  java
  • 俄罗斯方块(Win32实现,Codeblocks+GCC编译)

    缘起:

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

    程序效果:

     

    主要内容:

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

      如下图:

           

      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数组进行旋转操作,然后检测重合,如果有重合,则反向旋转回来。

    代码:

      1 #if defined(UNICODE) && !defined(_UNICODE)
      2 #define _UNICODE
      3 #elif defined(_UNICODE) && !defined(UNICODE)
      4 #define UNICODE
      5 #endif
      6 
      7 #include <tchar.h>
      8 #include <windows.h>
      9 #include <pthread.h>
     10 #include <stdio.h>
     11 #include <time.h>
     12 /*-----------------宏定义--------------------------------------------------------*/
     13 #define WIDTH 180
     14 #define HEIGHT 400
     15 #define LONG_SLEEP 300
     16 #define BKCOLOR RGB(238,238,238)//背景色
     17 /*-----------------变量----------------------------------------------------------*/
     18 static int shapes[7][4][4];//存储7个形状
     19 static int high_score[4]= {0,0,0,0};//前三个元素存储最高分,最后一个元素存储此次得分
     20 static int **shape;//当前形状
     21 static int **board;
     22 static int M=15;//显示的列数
     23 static int N=30;//显示的行数
     24 static int MM=M+8;//board的列数
     25 static int NN=N+4;//board的行数
     26 static int LEFT=4;//显示的最左一列
     27 static int RIGHT=LEFT+M-1;//显示的最右一列
     28 static int TOP=0;//显示的最上一列
     29 static int BOTTOM=N-1;//显示的最下一列
     30 static int score=0;
     31 static int row=0;//形状所在行
     32 static int column=MM/2;//形状坐在列
     33 static bool is_pause=false;
     34 static HBRUSH grey_brush =CreateSolidBrush (RGB(210,210,210));
     35 static HBRUSH white_brush =CreateSolidBrush (RGB(130,130,130));
     36 static HBRUSH bk_brush =CreateSolidBrush (BKCOLOR);
     37 static HPEN hPen = CreatePen(PS_SOLID,1,RGB(147,155,166));
     38 static int lattices_top=40;//上面留白
     39 static int lattices_left=20;//左侧留白
     40 static int width=WIDTH/M;//每个格子的宽度
     41 static int height=(HEIGHT-lattices_top)/N;//每个格子的高度
     42 /*-----------------函数-----------------------------------------------------------*/
     43 void add_score() ;
     44 bool check_is_lose() ;
     45 void clear_up() ;//消除没有空格子的行
     46 void* down_thread_function(void * args) ;//形状下落进程要执行的函数
     47 void exit_game(HWND hwnd) ;
     48 void give_new_shape() ;//随机生成一个新形状
     49 int handle_key(HWND hwnd,WPARAM wParam) ;
     50 int init_down_thread(HWND hwnd) ;//初始化形状下落进程
     51 int init_game(HWND hwnd) ;//初始化游戏程序
     52 void init_play() ;//初始化游戏数据
     53 bool is_legel() ;//检测形状在当前位置是否合法(即是否重合了非空的格子)
     54 int load_scores(int* a) ;//读取游戏最高分数据
     55 int load_shape() ;//从文件中加载7个形状
     56 void lose_game(HWND hwnd) ;
     57 int move_down(HWND hwnd) ;//形状下落
     58 int move_lr(HWND hwnd,int lr) ;//形状左右移动
     59 void paint_lattice(HDC hdc,int x,int y,int color) ;//显示一个格子
     60 void paint_UI(HDC hdc) ;//画界面
     61 void reset_rc() ;
     62 void rerotate_matrix(int mn) ;//顺时针旋转一个行列数为mn的方阵
     63 void rotate_matrix(int mn) ;//逆时针旋转一个行列数为mn的方阵
     64 int rotate_shape(HWND hwnd) ;//旋转当前形状并更新界面
     65 bool save_score(HWND hwnd) ;//保存最高分数据
     66 void shape_to_ground() ;//当前形状落地之后,更新board
     67 bool sort_scores(int* a) ;//对最高分和此次得分排序,若创造新纪录则返回true
     68 void update_UI(HWND hwnd) ;//更新界面,仅更新Rect区域(形状所在的那几行)内
     69 void update_UI_all(HWND hwnd) ;//更新界面,更新整个界面
     70 int write_scores(int* a) ;//写最高分数据
     71 
     72 
     73 
     74 
     75 /*  Declare Windows procedure  */
     76 LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);
     77 
     78 /*  Make the class name into a global variable  */
     79 TCHAR szClassName[ ] = _T("Tris");
     80 
     81 int WINAPI WinMain (HINSTANCE hThisInstance,
     82                     HINSTANCE hPrevInstance,
     83                     LPSTR lpszArgument,
     84                     int nCmdShow) {
     85     HWND hwnd;               /* This is the handle for our window */
     86     MSG messages;            /* Here messages to the application are saved */
     87     WNDCLASSEX wincl;        /* Data structure for the windowclass */
     88 
     89     /* The Window structure */
     90     wincl.hInstance = hThisInstance;
     91     wincl.lpszClassName = szClassName;
     92     wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
     93     wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
     94     wincl.cbSize = sizeof (WNDCLASSEX);
     95 
     96     /* Use default icon and mouse-pointer */
     97     wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
     98     wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
     99     wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    100     wincl.lpszMenuName = NULL;                 /* No menu */
    101     wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    102     wincl.cbWndExtra = 0;                      /* structure or the window instance */
    103     /* Use Windows's default colour as the background of the window */
    104     wincl.hbrBackground =bk_brush;
    105     /* Register the window class, and if it fails quit the program */
    106     if (!RegisterClassEx (&wincl))
    107         return 0;
    108 
    109     /* The class is registered, let's create the program*/
    110     hwnd = CreateWindowEx (
    111                0,                   /* Extended possibilites for variation */
    112                szClassName,         /* Classname */
    113                _T("Tris"),       /* Title Text */
    114                WS_OVERLAPPEDWINDOW, /* default window */
    115                CW_USEDEFAULT,       /* Windows decides the position */
    116                CW_USEDEFAULT,       /* where the window ends up on the screen */
    117                WIDTH+200,                 /* The programs width */
    118                HEIGHT+70,                 /* and height in pixels */
    119                HWND_DESKTOP,        /* The window is a child-window to desktop */
    120                NULL,                /* No menu */
    121                hThisInstance,       /* Program Instance handler */
    122                NULL                 /* No Window Creation data */
    123            );
    124 
    125     /* Make the window visible on the screen */
    126     ShowWindow (hwnd, nCmdShow);
    127 
    128     /* Run the message loop. It will run until GetMessage() returns 0 */
    129     while (GetMessage (&messages, NULL, 0, 0)) {
    130         /* Translate virtual-key messages into character messages */
    131         TranslateMessage(&messages);
    132         /* Send message to WindowProcedure */
    133         DispatchMessage(&messages);
    134     }
    135 
    136     /* The program return-value is 0 - The value that PostQuitMessage() gave */
    137     return messages.wParam;
    138 }
    139 //从文件中加载7个形状
    140 int load_shape() {
    141     FILE* f=fopen("shapes.txt","rb");
    142     if(f==NULL) {
    143         return -1;
    144     }
    145     for(int i=0; i<7; i++) {
    146         for(int j=0; j<4; j++) {
    147             for(int k=0; k<4; k++) {
    148                 if(fscanf(f,"%d",&shapes[i][j][k])!=1) {
    149                     return -1;
    150                 }
    151             }
    152         }
    153     }
    154     fclose(f);
    155     return 0;
    156 }
    157 //随机生成一个新形状
    158 void give_new_shape() {
    159     int shape_num=rand()%7;
    160     for(int i=0; i<4; i++) {
    161         for(int j=0; j<4; j++) {
    162             shape[i][j]=shapes[shape_num][i][j];
    163         }
    164     }
    165 }
    166 void add_score() {
    167     score+=100;
    168 }
    169 //消除没有空格子的行
    170 void clear_up() {
    171     for(int i=row; i<=row+3; i++) {
    172         if(i>BOTTOM)continue;
    173         bool there_is_blank=false;
    174         for(int j=LEFT; j<=RIGHT; j++) {
    175             if(board[i][j]==0) {
    176                 there_is_blank=true;
    177                 break;
    178             }
    179         }
    180         if(!there_is_blank) {
    181             add_score();
    182             for(int r=i; r>=1; r--) {
    183                 for(int c=LEFT; c<=RIGHT; c++) {
    184                     board[r][c]=board[r-1][c];
    185                 }
    186             }
    187         }
    188     }
    189 }
    190 //检测形状在当前位置是否合法(即是否重合了非空的格子)
    191 bool is_legel() {
    192     for(int i=0; i<4; i++) {
    193         for(int j=0; j<4; j++) {
    194             if(shape[i][j]==1&&board[row+i][column+j]==1) {
    195                 return false;
    196             }
    197         }
    198     }
    199     return true;
    200 }
    201 //逆时针旋转一个行列数为mn的方阵
    202 void rotate_matrix(int mn) {
    203     int** a=shape;
    204     int s=0;
    205     for(int n=mn; n>=1; n-=2) {
    206         for(int i=0; i<n-1; i++) {
    207             int t=a[s+i][s];
    208             a[s+i][s]=a[s][s+n-i-1];
    209             a[s][s+n-i-1]=a[s+n-i-1][s+n-1];
    210             a[s+n-i-1][s+n-1]=a[s+n-1][s+i];
    211             a[s+n-1][s+i]=t;
    212         }
    213         s++;
    214     }
    215 }
    216 //顺时针旋转一个行列数为mn的方阵
    217 void rerotate_matrix(int mn) {
    218     int** a=shape;
    219     int s=0;
    220     for(int n=mn; n>=1; n-=2) {
    221         for(int i=0; i<n-1; i++) {
    222             int t=a[s+i][s];
    223             a[s+i][s]=a[s+n-1][s+i];
    224             a[s+n-1][s+i]=a[s+n-i-1][s+n-1];
    225             a[s+n-i-1][s+n-1]=a[s][s+n-i-1];
    226             a[s][s+n-i-1]=t;
    227         }
    228         s++;
    229     }
    230 }
    231 //显示一个格子
    232 void paint_lattice(HDC hdc,int x,int y,int color) {
    233     if(x<TOP||x>BOTTOM||y<LEFT||y>RIGHT) {
    234         return ;
    235     }
    236     x-=TOP;
    237     y-=LEFT;
    238     int left=lattices_left+y*width;
    239     int right=lattices_left+y*width+width;
    240     int top=lattices_top+x*height;
    241     int bottom=lattices_top+x*height+height;
    242     MoveToEx (hdc,left,top, NULL) ;
    243     LineTo (hdc,right,top) ;
    244     MoveToEx (hdc,left,top, NULL) ;
    245     LineTo (hdc,left,bottom) ;
    246     MoveToEx (hdc,left,bottom, NULL) ;
    247     LineTo (hdc,right,bottom) ;
    248     MoveToEx (hdc,right,top, NULL) ;
    249     LineTo (hdc,right,bottom) ;
    250     SelectObject(hdc, grey_brush);
    251     if(color==0) {
    252         SelectObject(hdc, white_brush);
    253     }
    254     Rectangle(hdc,left,top,right,bottom);
    255 }
    256 //更新界面,仅更新Rect区域(形状所在的那几行)内
    257 void update_UI(HWND hwnd) {
    258     static RECT rect;
    259     rect.left=lattices_left;
    260     rect.right=lattices_left+M*width+width;
    261     rect.top=lattices_top+(row-1)*height;
    262     rect.bottom=lattices_top+(row+4)*height;
    263     InvalidateRect (hwnd,&rect, false) ;
    264 }
    265 //更新界面,更新整个界面
    266 void update_UI_all(HWND hwnd) {
    267     InvalidateRect (hwnd,NULL, false) ;
    268 }
    269 //画界面
    270 void paint_UI(HDC hdc) {
    271     SetBkColor(hdc,BKCOLOR);
    272     SelectObject(hdc,hPen);  //选用画笔
    273     char score_str[20];
    274     sprintf(score_str,"Score:%d",score);
    275     TextOut(hdc,10,10,score_str,strlen(score_str));
    276     sprintf(score_str,"Highest Scores:");
    277     TextOut(hdc,WIDTH+50,50,score_str,strlen(score_str));
    278     for(int i=0; i<3; i++) {
    279         sprintf(score_str,"%d",high_score[i]);
    280         TextOut(hdc,WIDTH+50,50+(i+1)*20,score_str,strlen(score_str));
    281     }
    282     for(int i=TOP; i<=BOTTOM; i++) {
    283         for(int j=LEFT; j<=RIGHT; j++) {
    284             paint_lattice(hdc,i,j,board[i][j]);
    285         }
    286     }
    287     for(int i=0; i<4; i++) {
    288         for(int j=0; j<4; j++) {
    289             if(shape[i][j]==1)
    290                 paint_lattice(hdc,row+i,column+j,shape[i][j]);
    291         }
    292     }
    293 }
    294 //旋转当前形状并更新界面
    295 int rotate_shape(HWND hwnd) {
    296     int mn=4;
    297     rotate_matrix(mn);
    298     if(!is_legel()) {
    299         rerotate_matrix(mn);
    300     }
    301     update_UI(hwnd);
    302 }
    303 void reset_rc() {
    304     row=0;
    305     column=MM/2-2;
    306 }
    307 //读取游戏最高分数据
    308 int load_scores(int* a) {
    309     FILE* f=fopen("scores.txt","r");
    310     if(f==NULL)return -1;
    311     fscanf(f,"%d%d%d",&a[0],&a[1],&a[2]);
    312     return 0;
    313 }
    314 //初始化游戏数据
    315 void init_play() {
    316     load_scores(high_score);
    317     for(int i=0; i<NN; i++) {
    318         for(int j=0; j<MM; j++) {
    319             board[i][j]=0;
    320         }
    321     }
    322     for(int i=0; i<N; i++) {
    323         for(int j=0; j<LEFT; j++) {
    324             board[i][j]=1;
    325         }
    326     }
    327     for(int i=0; i<N; i++) {
    328         for(int j=RIGHT+1; j<MM; j++) {
    329             board[i][j]=1;
    330         }
    331     }
    332     for(int i=BOTTOM+1; i<NN; i++) {
    333         for(int j=0; j<MM; j++) {
    334             board[i][j]=1;
    335         }
    336     }
    337     reset_rc();
    338     score=0;
    339     give_new_shape();
    340     is_pause=false;
    341     return ;
    342 }
    343 bool check_is_lose() {
    344     if(row==0)return true;
    345     return false;
    346 }
    347 //对最高分和此次得分排序,若创造新纪录则返回true
    348 bool sort_scores(int* a) {
    349     int temp=a[3];
    350     for(int i=0; i<4; i++) {
    351         for(int j=0; j<3; j++) {
    352             if(a[j]<a[j+1]) {
    353                 int t=a[j];
    354                 a[j]=a[j+1];
    355                 a[j+1]=t;
    356             }
    357         }
    358     }
    359     if(temp>a[3])return true;
    360     return false;
    361 }
    362 //写最高分数据
    363 int write_scores(int* a) {
    364     FILE* f=fopen("scores.txt","w");
    365     if(f==NULL)return -1;
    366     fprintf(f,"%d\n%d\n%d\n",a[0],a[1],a[2]);
    367     return 0;
    368 }
    369 //保存最高分数据
    370 bool save_score(HWND hwnd) {
    371     high_score[3]=score;
    372     bool made_record=sort_scores(high_score);
    373     if(write_scores(high_score)!=0) {
    374         MessageBox(hwnd,"Write file error.Program will exit.","Error",NULL);
    375         DestroyWindow(hwnd);
    376     }
    377     return made_record;
    378 }
    379 void lose_game(HWND hwnd) {
    380     if(is_pause)return ;
    381     is_pause=true;
    382     char message[200]="You lose the Game.\n";
    383     char title[50]="Game Over";
    384     if(save_score(hwnd)) {
    385         strcat(message,"You have made a new record.\n");
    386         char score_str[100];
    387         sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[0],high_score[1],high_score[2]);
    388         strcat(message,score_str);
    389     }
    390     strcat(message,"\nPlay again?\n");
    391     if(MessageBox(hwnd,message,title,MB_YESNO)==IDYES) {
    392         init_play();
    393         update_UI_all(hwnd);
    394     } else {
    395         exit(0);
    396     }
    397 }
    398 void exit_game(HWND hwnd) {
    399     is_pause=true;
    400     char message[200]="";
    401     char title[50]="Exit";
    402     if(save_score(hwnd)) {
    403         strcat(message,"You have made a new record.\n");
    404         char score_str[100];
    405         sprintf(score_str,"The Highest Scores:\n%d\n%d\n%d\n",high_score[0],high_score[1],high_score[2]);
    406         strcat(message,score_str);
    407         MessageBox(hwnd,message,title,NULL);
    408     }
    409     exit(0);
    410 }
    411 //当前形状落地之后,更新board
    412 void shape_to_ground() {
    413     for(int i=0; i<4; i++) {
    414         for(int j=0; j<4; j++) {
    415             board[row+i][column+j]=shape[i][j]==1?1:board[row+i][column+j];
    416         }
    417     }
    418 }
    419 //形状下落
    420 int move_down(HWND hwnd) {
    421     row++;
    422     if(!is_legel()) {
    423         row--;
    424         if(check_is_lose()) {
    425             lose_game(hwnd);
    426             return 0;
    427         }
    428         shape_to_ground();
    429         clear_up();
    430         update_UI_all(hwnd);
    431         reset_rc();
    432         give_new_shape();
    433     }
    434     update_UI(hwnd);
    435 }
    436 //进程参数结构体
    437 struct thread_arg {
    438     HWND arg_hwnd;
    439 };
    440 //形状下落进程要执行的函数
    441 void* down_thread_function(void * args) {
    442     thread_arg *arg=(thread_arg*)args;
    443     HWND dhwnd=arg->arg_hwnd;
    444     while(true) {
    445         if(is_pause) {
    446             Sleep(300);
    447             continue;
    448         }
    449         move_down(dhwnd);
    450         Sleep(LONG_SLEEP);
    451     }
    452 }
    453 //初始化形状下落进程
    454 int init_down_thread(HWND hwnd) {
    455     int ret;
    456     pthread_t t;
    457     thread_arg *argp=new thread_arg;
    458     argp->arg_hwnd=hwnd;
    459     ret=pthread_create(&t,NULL,down_thread_function,argp);
    460     delete argp;
    461     if(ret!=0) {
    462         return -1;
    463     }
    464     return 0;
    465 }
    466 //初始化游戏程序
    467 int init_game(HWND hwnd) {
    468     board=new int*[NN];
    469     for(int i=0; i<NN; i++) {
    470         board[i]=new int[MM];
    471     }
    472     shape=new int*[4];
    473     for(int i=0; i<4; i++) {
    474         shape[i]=new int[4];
    475     }
    476     srand(time(0));
    477     if(load_shape()!=0) {
    478         MessageBox(hwnd,"Read file error.Program will exit.","Error",NULL);
    479         exit(-1);
    480     }
    481     init_play();
    482     update_UI_all(hwnd);
    483     if(init_down_thread(hwnd)!=0) {
    484         MessageBox(hwnd,"Thread error.Program will exit.","Error",NULL);
    485         exit(-1);
    486     }
    487     return 0;
    488 }
    489 //形状左右移动
    490 int move_lr(HWND hwnd,int lr) {
    491     int temp=column;
    492     if(lr==0)column--;
    493     else {
    494         column++;
    495     }
    496     if(!is_legel()) {
    497         column=temp;
    498     }
    499     update_UI(hwnd);
    500 }
    501 int handle_key(HWND hwnd,WPARAM wParam) {
    502     if(wParam==VK_ESCAPE) {//ESC退出
    503         exit_game(hwnd);
    504     }
    505     if(wParam==VK_SPACE) {//空格暂停
    506         is_pause=!is_pause;
    507     }
    508     if(is_pause==true) {
    509         Sleep(300);
    510         return 0;
    511     }
    512     if(wParam==VK_UP) {
    513         rotate_shape(hwnd);
    514     }
    515     if(wParam==VK_DOWN) {
    516         move_down(hwnd);
    517     }
    518     if(wParam==VK_LEFT) {
    519         move_lr(hwnd,0);
    520     }
    521     if(wParam==VK_RIGHT) {
    522         move_lr(hwnd,1);
    523     }
    524     return 0;
    525 }
    526 /*  This function is called by the Windows function DispatchMessage()  */
    527 HWND hwnd;
    528 LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
    529     static HDC hdc;
    530     static HDC hdcBuffer;
    531     static HBITMAP hBitMap;
    532     static PAINTSTRUCT ps ;
    533     switch (message) {                /* handle the messages */
    534     case WM_CREATE:
    535         init_game(hwnd);
    536         break;
    537     case WM_KEYDOWN:
    538         handle_key(hwnd,wParam);
    539         break;
    540     case WM_DESTROY:
    541         exit_game(hwnd);
    542         PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
    543         break;
    544     case WM_PAINT:
    545         hdc = BeginPaint (hwnd, &ps) ;
    546         paint_UI(hdc);
    547         EndPaint (hwnd, &ps) ;
    548         break;
    549     default:                      /* for messages that we don't deal with */
    550         return DefWindowProc (hwnd, message, wParam, lParam);
    551     }
    552     return 0;
    553 }

    嗯,后来发现 Codeblocks 可以在设置里设置不限时间地玩BYOGames。。。尬。。

    程序写于2016年五一期间

    随笔写于2016.5.8

    END

  • 相关阅读:
    C#后台制作之数据库(Access数据库+datagirdview控件显示+串口数据存储)
    Zedboardwebcam设计问题篇(六)opencv处理帧数据之算法改进
    Zedboardwebcam设计问题篇(二)V4l2 Capture Sequence 捕获过程
    Zedboardwebcam设计问题篇(五)opencv处理帧数据,函数代码实现
    Zedboardwebcam设计问题篇(七)NFS服务器配置
    Zedboard摄像头获取视频设计问题篇(四)OpenCV+QT配置显示图片
    C#后台制作之数据库(二、如何清除显示以及将数据库数据导出到excel表格文件中)
    Android高手进阶教程(二)之Android Launcher抽屉类SlidingDrawer的使用!
    TabHost和TabWidget写出微信下面选项卡的界面
    android内存处理机制
  • 原文地址:https://www.cnblogs.com/maxuewei2/p/5470406.html
Copyright © 2011-2022 走看看