程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> 俄羅斯方塊(Win32實現,Codeblocks+GCC編譯),codeblocksgcc

俄羅斯方塊(Win32實現,Codeblocks+GCC編譯),codeblocksgcc

編輯:C++入門知識

俄羅斯方塊(Win32實現,Codeblocks+GCC編譯),codeblocksgcc


緣起:

  在玩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 }

 

 

程序寫於2016年五一期間

隨筆寫於2016.5.8

 

END

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved