一、首先放上全部源码:
1 #include <stdio.h>
2 #include <windows.h>
3 #include <conio.h>
4 #include <time.h>
5 //游戏窗口
6 #define FrameX 4 //游戏窗口左上角的X轴坐标
7 #define FrameY 4 //游戏窗口左上角的Y轴坐标
8 #define Frame_height 20 //游戏窗口的高度
9 #define Frame_width 18 //游戏窗口的宽度
10 //定义全局变量
11 int i,j,temp,temp1,temp2; //temp,temp1,temp2用于记住和转换方块变量的值
12 int a[80][80]={0}; //标记游戏屏幕的图案:2,1,0分别表示该位置为游戏边框、方块、无图案;初始化为无图案
13 int b[4]; //标记4个"口"方块:1表示有方块,0表示无方块
14
15 //声明俄罗斯方块的结构体
16 struct Tetris
17 {
18 int x; //中心方块的x轴坐标
19 int y; //中心方块的y轴坐标
20 int flag; //标记方块类型的序号
21 int next; //下一个俄罗斯方块类型的序号
22 int speed; //俄罗斯方块移动的速度
23 int count; //产生俄罗斯方块的个数
24 int score; //游戏的分数
25 int level; //游戏的等级
26 };
27 //函数原型声明
28 //光标移到指定位置
29 void gotoxy(HANDLE hOut, int x, int y);
30 //制作游戏窗口
31 void make_frame();
32 //随机产生方块类型的序号
33 void get_flag(struct Tetris *);
34 //制作俄罗斯方块
35 void make_tetris(struct Tetris *);
36 //打印俄罗斯方块
37 void print_tetris(HANDLE hOut,struct Tetris *);
38 //清除俄罗斯方块的痕迹
39 void clear_tetris(HANDLE hOut,struct Tetris *);
40 //判断是否能移动,返回值为1,能移动,否则,不动
41 int if_moveable(struct Tetris *);
42 //判断是否满行,并删除满行的俄罗斯方块
43 void del_full(HANDLE hOut,struct Tetris *);
44 //开始游戏
45 void start_game();
46
47 int main()
48 {
49 //制作游戏窗口
50 make_frame();
51 //开始游戏
52 start_game();
53 }
54 /******光标移到指定位置**************************************************************/
55 void gotoxy(HANDLE hOut, int x, int y)
56 {
57 COORD pos;
58 pos.X = x; //横坐标
59 pos.Y = y; //纵坐标
60 SetConsoleCursorPosition(hOut, pos);
61 }
62 /******制作游戏窗口******************************************************************/
63 void make_frame()
64 {
65 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量
66 gotoxy(hOut,FrameX+Frame_width-5,FrameY-2); //打印游戏名称
67 printf("俄罗斯方块");
68 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+7); //打印选择菜单
69 printf("**********下一个方块:");
70 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+13);
71 printf("**********");
72 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+17);
73 printf("↑键:变体");
74 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+19);
75 printf("空格:暂停游戏");
76 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+15);
77 printf("Esc :退出游戏");
78 gotoxy(hOut,FrameX,FrameY); //打印框角并记住该处已有图案
79 printf("╔");
80 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY);
81 printf("╗");
82 gotoxy(hOut,FrameX,FrameY+Frame_height);
83 printf("╚");
84 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+Frame_height);
85 printf("╝");
86 a[FrameX][FrameY+Frame_height]=2;
87 a[FrameX+2*Frame_width-2][FrameY+Frame_height]=2;
88 for(i=2;i<2*Frame_width-2;i+=2)
89 {
90 gotoxy(hOut,FrameX+i,FrameY);
91 printf("═"); //打印上横框
92 }
93 for(i=2;i<2*Frame_width-2;i+=2)
94 {
95 gotoxy(hOut,FrameX+i,FrameY+Frame_height);
96 printf("═"); //打印下横框
97 a[FrameX+i][FrameY+Frame_height]=2; //记住下横框有图案
98 }
99 for(i=1;i<Frame_height;i++)
100 {
101 gotoxy(hOut,FrameX,FrameY+i);
102 printf("║"); //打印左竖框
103 a[FrameX][FrameY+i]=2; //记住左竖框有图案
104 }
105 for(i=1;i<Frame_height;i++)
106 {
107 gotoxy(hOut,FrameX+2*Frame_width-2,FrameY+i);
108 printf("║"); //打印右竖框
109 a[FrameX+2*Frame_width-2][FrameY+i]=2; //记住右竖框有图案
110 }
111 }
112 /******制作俄罗斯方块********************************************************************/
113 void make_tetris(struct Tetris *tetris)
114 {
115 a[tetris->x][tetris->y]=b[0]; //中心方块位置的图形状态:1-有,0-无
116 switch(tetris->flag) //共6大类,19种类型
117 {
118 case 1: //田字方块
119 {
120 a[tetris->x][tetris->y-1]=b[1];
121 a[tetris->x+2][tetris->y-1]=b[2];
122 a[tetris->x+2][tetris->y]=b[3];
123 break;
124 }
125 case 2: //直线方块:----
126 {
127 a[tetris->x-2][tetris->y]=b[1];
128 a[tetris->x+2][tetris->y]=b[2];
129 a[tetris->x+4][tetris->y]=b[3];
130 break;
131 }
132 case 3: //直线方块: |
133 {
134 a[tetris->x][tetris->y-1]=b[1];
135 a[tetris->x][tetris->y-2]=b[2];
136 a[tetris->x][tetris->y+1]=b[3];
137 break;
138 }
139 case 4: //T字方块
140 {
141 a[tetris->x-2][tetris->y]=b[1];
142 a[tetris->x+2][tetris->y]=b[2];
143 a[tetris->x][tetris->y+1]=b[3];
144 break;
145 }
146 case 5: //T字顺时针转90度方块
147 {
148 a[tetris->x][tetris->y-1]=b[1];
149 a[tetris->x][tetris->y+1]=b[2];
150 a[tetris->x-2][tetris->y]=b[3];
151 break;
152 }
153 case 6: //T字顺时针转180度方块
154 {
155 a[tetris->x][tetris->y-1]=b[1];
156 a[tetris->x-2][tetris->y]=b[2];
157 a[tetris->x+2][tetris->y]=b[3];
158 break;
159 }
160 case 7: //T字顺时针转270度方块
161 {
162 a[tetris->x][tetris->y-1]=b[1];
163 a[tetris->x][tetris->y+1]=b[2];
164 a[tetris->x+2][tetris->y]=b[3];
165 break;
166 }
167 case 8: //Z字方块
168 {
169 a[tetris->x][tetris->y+1]=b[1];
170 a[tetris->x-2][tetris->y]=b[2];
171 a[tetris->x+2][tetris->y+1]=b[3];
172 break;
173 }
174 case 9: //Z字顺时针转90度方块
175 {
176 a[tetris->x][tetris->y-1]=b[1];
177 a[tetris->x-2][tetris->y]=b[2];
178 a[tetris->x-2][tetris->y+1]=b[3];
179 break;
180 }
181 case 10: //Z字顺时针转180度方块
182 {
183 a[tetris->x][tetris->y-1]=b[1];
184 a[tetris->x-2][tetris->y-1]=b[2];
185 a[tetris->x+2][tetris->y]=b[3];
186 break;
187 }
188 case 11: //Z字顺时针转270度方块
189 {
190 a[tetris->x][tetris->y+1]=b[1];
191 a[tetris->x+2][tetris->y-1]=b[2];
192 a[tetris->x+2][tetris->y]=b[3];
193 break;
194 }
195 case 12: //7字方块
196 {
197 a[tetris->x][tetris->y-1]=b[1];
198 a[tetris->x][tetris->y+1]=b[2];
199 a[tetris->x-2][tetris->y-1]=b[3];
200 break;
201 }
202 case 13: //7字顺时针转90度方块
203 {
204 a[tetris->x-2][tetris->y]=b[1];
205 a[tetris->x-2][tetris->y+1]=b[2];
206 a[tetris->x+2][tetris->y]=b[3];
207 break;
208 }
209 case 14: //7字顺时针转180度方块
210 {
211 a[tetris->x][tetris->y-1]=b[1];
212 a[tetris->x][tetris->y+1]=b[2];
213 a[tetris->x+2][tetris->y+1]=b[3];
214 break;
215 }
216 case 15: //7字顺时针转270度方块
217 {
218 a[tetris->x-2][tetris->y]=b[1];
219 a[tetris->x+2][tetris->y-1]=b[2];
220 a[tetris->x+2][tetris->y]=b[3];
221 break;
222 }
223 case 16: //倒7字方块
224 {
225 a[tetris->x][tetris->y+1]=b[1];
226 a[tetris->x][tetris->y-1]=b[2];
227 a[tetris->x+2][tetris->y-1]=b[3];
228 break;
229 }
230 case 17: //倒7字顺指针转90度方块
231 {
232 a[tetris->x-2][tetris->y]=b[1];
233 a[tetris->x-2][tetris->y-1]=b[2];
234 a[tetris->x+2][tetris->y]=b[3];
235 break;
236 }
237 case 18: //倒7字顺时针转180度方块
238 {
239 a[tetris->x][tetris->y-1]=b[1];
240 a[tetris->x][tetris->y+1]=b[2];
241 a[tetris->x-2][tetris->y+1]=b[3];
242 break;
243 }
244 case 19: //倒7字顺时针转270度方块
245 {
246 a[tetris->x-2][tetris->y]=b[1];
247 a[tetris->x+2][tetris->y+1]=b[2];
248 a[tetris->x+2][tetris->y]=b[3];
249 break;
250 }
251 }
252 }
253 //******判断是否可动*************************************************************************/
254 int if_moveable(struct Tetris *tetris)
255 {
256 if(a[tetris->x][tetris->y]!=0)//当中心方块位置上有图案时,返回值为0,即不可移动
257 {
258 return 0;
259 }
260 else
261 {
262 if( //当为田字方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
263 ( tetris->flag==1 && ( a[tetris->x][tetris->y-1]==0 &&
264 a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
265 //或为直线方块且除中心方块位置外,其他"口"字方块位置上无图案时,返回值为1,即可移动
266 ( tetris->flag==2 && ( a[tetris->x-2][tetris->y]==0 &&
267 a[tetris->x+2][tetris->y]==0 && a[tetris->x+4][tetris->y]==0 ) ) ||
268 ( tetris->flag==3 && ( a[tetris->x][tetris->y-1]==0 &&
269 a[tetris->x][tetris->y-2]==0 && a[tetris->x][tetris->y+1]==0 ) ) ||
270 ( tetris->flag==4 && ( a[tetris->x-2][tetris->y]==0 &&
271 a[tetris->x+2][tetris->y]==0 && a[tetris->x][tetris->y+1]==0 ) ) ||
272 ( tetris->flag==5 && ( a[tetris->x][tetris->y-1]==0 &&
273 a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y]==0 ) ) ||
274 ( tetris->flag==6 && ( a[tetris->x][tetris->y-1]==0 &&
275 a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
276 ( tetris->flag==7 && ( a[tetris->x][tetris->y-1]==0 &&
277 a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
278 ( tetris->flag==8 && ( a[tetris->x][tetris->y+1]==0 &&
279 a[tetris->x-2][tetris->y]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
280 ( tetris->flag==9 && ( a[tetris->x][tetris->y-1]==0 &&
281 a[tetris->x-2][tetris->y]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
282 ( tetris->flag==10 && ( a[tetris->x][tetris->y-1]==0 &&
283 a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
284 ( tetris->flag==11 && ( a[tetris->x][tetris->y+1]==0 &&
285 a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
286 ( tetris->flag==12 && ( a[tetris->x][tetris->y-1]==0 &&
287 a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y-1]==0 ) ) ||
288 ( tetris->flag==13 && ( a[tetris->x-2][tetris->y]==0 &&
289 a[tetris->x-2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
290 ( tetris->flag==14 && ( a[tetris->x][tetris->y-1]==0 &&
291 a[tetris->x][tetris->y+1]==0 && a[tetris->x+2][tetris->y+1]==0 ) ) ||
292 ( tetris->flag==15 && ( a[tetris->x-2][tetris->y]==0 &&
293 a[tetris->x+2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
294 ( tetris->flag==16 && ( a[tetris->x][tetris->y+1]==0 &&
295 a[tetris->x][tetris->y-1]==0 && a[tetris->x+2][tetris->y-1]==0 ) ) ||
296 ( tetris->flag==17 && ( a[tetris->x-2][tetris->y]==0 &&
297 a[tetris->x-2][tetris->y-1]==0 && a[tetris->x+2][tetris->y]==0 ) ) ||
298 ( tetris->flag==18 && ( a[tetris->x][tetris->y-1]==0 &&
299 a[tetris->x][tetris->y+1]==0 && a[tetris->x-2][tetris->y+1]==0 ) ) ||
300 ( tetris->flag==19 && ( a[tetris->x-2][tetris->y]==0 &&
301 a[tetris->x+2][tetris->y+1]==0 && a[tetris->x+2][tetris->y]==0 ) ) )
302 {
303 return 1;
304 }
305 }
306 return 0;
307 }
308 /******随机产生俄罗斯方块类型的序号**********************************************************/
309 void get_flag(struct Tetris *tetris)
310 {
311 tetris->count++; //记住产生方块的个数
312 srand((unsigned)time(NULL)); //初始化随机数
313 if(tetris->count==1)
314 {
315 tetris->flag = rand()%19+1; //记住第一个方块的序号
316 }
317 tetris->next = rand()%19+1; //记住下一个方块的序号
318 }
319 /******打印俄罗斯方块**********************************************************************/
320 void print_tetris(HANDLE hOut,struct Tetris *tetris)
321 {
322 for(i=0;i<4;i++)
323 {
324 b[i]=1; //数组b[4]的每个元素的值都为1
325 }
326 make_tetris(tetris); //制作俄罗斯方块
327 for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
328 {
329 for(j=tetris->y-2;j<=tetris->y+1;j++)
330 {
331 if( a[i][j]==1 && j>FrameY )
332 {
333 gotoxy(hOut,i,j);
334 printf("□"); //打印边框内的方块
335 }
336 }
337 }
338 //打印菜单信息
339 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+1);
340 printf("level : %d",tetris->level);
341 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+3);
342 printf("score : %d",tetris->score);
343 gotoxy(hOut,FrameX+2*Frame_width+3,FrameY+5);
344 printf("speed : %dms",tetris->speed);
345 }
346 /******清除俄罗斯方块的痕迹****************************************************************/
347 void clear_tetris(HANDLE hOut,struct Tetris *tetris)
348 {
349 for(i=0;i<4;i++)
350 {
351 b[i]=0; //数组b[4]的每个元素的值都为0
352 }
353 make_tetris(tetris); //制作俄罗斯方块
354 for( i=tetris->x-2; i<=tetris->x+4; i+=2 )
355 {
356 for(j=tetris->y-2;j<=tetris->y+1;j++)
357 {
358 if( a[i][j]==0 && j>FrameY )
359 {
360 gotoxy(hOut,i,j);
361 printf(" "); //清除方块
362 }
363 }
364 }
365 }
366 /******判断是否满行并删除满行的俄罗斯方块****************************************************/
367 void del_full(HANDLE hOut,struct Tetris *tetris)
368 { //当某行有Frame_width-2个方块时,则满行
369 int k,del_count=0; //分别用于记录某行方块的个数和删除方块的行数的变量
370 for(j=FrameY+Frame_height-1;j>=FrameY+1;j--)
371 {
372 k=0;
373 for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)
374 {
375 if(a[i][j]==1) //竖坐标依次从下往上,横坐标依次由左至右判断是否满行
376 {
377 k++; //记录此行方块的个数
378 if(k==Frame_width-2)
379 {
380 for(k=FrameX+2;k<FrameX+2*Frame_width-2;k+=2)
381 { //删除满行的方块
382 a[k][j]=0;
383 gotoxy(hOut,k,j);
384 printf(" ");
385 Sleep(1);
386 }
387 for(k=j-1;k>FrameY;k--)
388 { //如果删除行以上的位置有方块,则先清除,再将方块下移一个位置
389 for(i=FrameX+2;i<FrameX+2*Frame_width-2;i+=2)
390 {
391 if(a[i][k]==1)
392 {
393 a[i][k]=0;
394 gotoxy(hOut,i,k);
395 printf(" ");
396 a[i][k+1]=1;
397 gotoxy(hOut,i,k+1);
398 printf("□");
399 }
400 }
401 }
402 j++; //方块下移后,重新判断删除行是否满行
403 del_count++; //记录删除方块的行数
404 }
405 }
406 }
407 }
408 tetris->score+=100*del_count; //每删除一行,得100分
409 if( del_count>0 && ( tetris->score%1000==0 || tetris->score/1000>tetris->level-1 ) )
410 { //如果得1000分即累计删除10行,速度加快20ms并升一级
411 tetris->speed-=20;
412 tetris->level++;
413 }
414 }
415 /******开始游戏******************************************************************************/
416 void start_game()
417 {
418 HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); //定义显示器句柄变量
419 struct Tetris t,*tetris=&t; //定义结构体的指针并指向结构体变量
420 unsigned char ch; //定义接收键盘输入的变量
421 tetris->count=0; //初始化俄罗斯方块数为0个
422 tetris->speed=300; //初始移动速度为300ms
423 tetris->score=0; //初始游戏的分数为0分
424 tetris->level=1; //初始游戏为第1关
425 while(1)
426 {//循环产生方块,直至游戏结束
427 get_flag(tetris); //得到产生俄罗斯方块类型的序号
428 temp=tetris->flag; //记住当前俄罗斯方块序号
429 //打印下一个俄罗斯方块的图形(右边窗口)
430 tetris->x=FrameX+2*Frame_width+6;
431 tetris->y=FrameY+10;
432 tetris->flag = tetris->next;
433 print_tetris(hOut,tetris);
434 tetris->x=FrameX+Frame_width; //初始中心方块x坐标
435 tetris->y=FrameY-1; //初始中心方块y坐标
436 tetris->flag=temp; //取出当前的俄罗斯方块序号
437 while(1)
438 {//控制方块方向,直至方块不再下移
439 label:print_tetris(hOut,tetris);//打印俄罗斯方块
440 Sleep(tetris->speed); //延缓时间
441 clear_tetris(hOut,tetris); //清除痕迹
442 temp1=tetris->x; //记住中心方块横坐标的值
443 temp2=tetris->flag; //记住当前俄罗斯方块序号
444 if(kbhit())
445 { //判断是否有键盘输入,有则用ch↓接收
446 ch=getch();
447 if(ch==75) //按←键则向左动,中心横坐标减2
448 {
449 tetris->x-=2;
450 }
451 if(ch==77) //按→键则向右动,中心横坐标加2
452 {
453 tetris->x+=2;
454 }
455 if(ch==72) //按↑键则变体即当前方块顺时针转90度
456 {
457 if( tetris->flag>=2 && tetris->flag<=3 )
458 {
459 tetris->flag++;
460 tetris->flag%=2;
461 tetris->flag+=2;
462 }
463 if( tetris->flag>=4 && tetris->flag<=7 )
464 {
465 tetris->flag++;
466 tetris->flag%=4;
467 tetris->flag+=4;
468 }
469 if( tetris->flag>=8 && tetris->flag<=11 )
470 {
471 tetris->flag++;
472 tetris->flag%=4;
473 tetris->flag+=8;
474 }
475 if( tetris->flag>=12 && tetris->flag<=15 )
476 {
477 tetris->flag++;
478 tetris->flag%=4;
479 tetris->flag+=12;
480 }
481 if( tetris->flag>=16 && tetris->flag<=19 )
482 {
483 tetris->flag++;
484 tetris->flag%=4;
485 tetris->flag+=16;
486 }
487 }
488 if(ch==32) //按空格键,暂停
489 {
490 print_tetris(hOut,tetris);
491 while(1)
492 {
493 if(kbhit()) //再按空格键,继续游戏
494 {
495 ch=getch();
496 if(ch==32)
497 {
498 goto label;
499 }
500 }
501 }
502 }
503 if(if_moveable(tetris)==0) //如果不可动,上面操作无效
504 {
505 tetris->x=temp1;
506 tetris->flag=temp2;
507 }
508 else //如果可动,执行操作
509 {
510 goto label;
511 }
512 }
513 tetris->y++; //如果没有操作指令,方块向下移动
514 if(if_moveable(tetris)==0) //如果向下移动且不可动,方块放在此处
515 {
516 tetris->y--;
517 print_tetris(hOut,tetris);
518 del_full(hOut,tetris);
519 break;
520 }
521 }
522 for(i=tetris->y-2;i<tetris->y+2;i++)
523 {//游戏结束条件:方块触到框顶位置
524 if(i==FrameY)
525 {
526 j=0; //如果游戏结束,j=0
527 }
528 }
529 if(j==0)
530 {
531 system("cls");
532 getch();
533 break;
534 }
535 //清除下一个俄罗斯方块的图形(右边窗口)
536 tetris->flag = tetris->next;
537 tetris->x=FrameX+2*Frame_width+6;
538 tetris->y=FrameY+10;
539 clear_tetris(hOut,tetris);
540 }
541 }
View Code
二、整个游戏的流程图
三、函数解析