+ -
当前位置:首页 → 问答吧 → [原创]贡献一个蛋疼的俄罗斯方块小游戏

[原创]贡献一个蛋疼的俄罗斯方块小游戏

时间:2010-07-28

来源:互联网

本帖最后由 dave_cn 于 2010-07-28 20:20 编辑

我在Ubuntu 10.04下测试过,可以正常运行。不过界面让人蛋疼。
代码用到了NCURSES库。编译的时候链一下ncurses库就可以了,如:
cc -Wall -O2 -o c01 file.c -lncurses
界面:
下载 (9.4 KB)
2010-07-28 20:20

还请各位多多指教。
  1. /***************************************
  2. *
  3. * TETRIS
  4. *
  5. * author: dave
  6. * date  : 2010/07/28
  7. *
  8. ***************************************/
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <string.h>
  12. #include <time.h>
  13. #include <sys/select.h>
  14. #include <sys/time.h>
  15. #include <sys/types.h>
  16. #include <unistd.h>
  17. #include <ncurses.h>

  18. #define TETRADS_LEN   4
  19. #define GAMEWIN_YLEN  20
  20. #define GAMEWIN_XLEN  10
  21. #define GAMEWIN_Y     1
  22. #define GAMEWIN_X     2
  23. #define INFOWIN_YLEN  10
  24. #define INFOWIN_XLEN  10
  25. #define INFOWIN_Y     GAMEWIN_Y
  26. #define INFOWIN_X     (GAMEWIN_X + GAMEWIN_XLEN*2 + 5)
  27. #define PIC_BLOCK     '#'
  28. #define PIC_NULL      ' '

  29. #define _X(x)         ((x)*2)

  30. #define BASEWIN \
  31.     WINDOW *win; \
  32.     void   (*init)(); \
  33.     void   (*show)();

  34. #define EXCHANGE_XY(_pos) \
  35.     do { \
  36.         (_pos).x = (_pos).y + (_pos).x; \
  37.         (_pos).y = (_pos).x - (_pos).y; \
  38.         (_pos).x -= (_pos).y; \
  39.     } while (0)

  40. #define EXCHANGE_2Y(_pos) \
  41.         (_pos).y = 2 - (_pos).y

  42. #define COPY_TETRADS(_dest, _src) \
  43.     memcpy(&(_dest), &(_src), sizeof(Tetrads))

  44. #define TETRISNEW(_p, _t) \
  45.     do { \
  46.         (_p) = (_t*)malloc(sizeof(_t)); \
  47.         (_p)->init = init##_t; \
  48.         (_p)->show = show##_t; \
  49.     } while (0)

  50. #define TETRISDEL(_p) \
  51.     do { \
  52.         delwin(_p->win); \
  53.         free(_p); \
  54.     } while (0)

  55. /* 俄罗斯方块的7种方块(Tetromino) */
  56. typedef enum {
  57.     TETRADS_S = 0,
  58.     TETRADS_Z,
  59.     TETRADS_L,
  60.     TETRADS_J,
  61.     TETRADS_O,
  62.     TETRADS_T,
  63.     TETRADS_I,
  64.    
  65.     TETRADS_MAX
  66. } ETetrads;

  67. typedef enum {
  68.     DIR_UP = 0,
  69.     DIR_DOWN,
  70.     DIR_LEFT,
  71.     DIR_RIGHT,
  72.    
  73.     DIR_MAX
  74. } EDirction;

  75. typedef enum {
  76.     TETRIS_STATE_NEW,
  77.     TETRIS_STATE_MOVE,
  78.     TETRIS_STATE_STOP,
  79.    
  80.     TETRIS_STATE_MAX,
  81. } ETetrisState;

  82. typedef struct {
  83.     int y;
  84.     int x;
  85. } Point;

  86. typedef struct {
  87.     ETetrads type;
  88.     Point    blocks[TETRADS_LEN];
  89. } Tetrads;

  90. /*** BEGIN : 界面显示 ***/ /* 将界面显示与数据处理分离 */
  91. typedef struct _BaseWin {
  92.     /**
  93.      * WINDOW *win;
  94.      * void   (*init)();
  95.      * void   (*show)();
  96.      */
  97.     BASEWIN
  98. } BaseWin;

  99. typedef struct _GameWin {
  100.     /**
  101.      * WINDOW *win;
  102.      * void   (*init)();
  103.      * void   (*show)();
  104.      */
  105.     BASEWIN

  106.     char    background[GAMEWIN_YLEN][GAMEWIN_XLEN];
  107.     char    matrix[GAMEWIN_YLEN][GAMEWIN_XLEN];
  108.     int     level;
  109.     Point   pos;
  110.     Tetrads curTetrads;
  111. } GameWin;

  112. typedef struct _InfoWin {
  113.     /**
  114.      * WINDOW *win;
  115.      * void   (*init)();
  116.      * void   (*show)();
  117.      */
  118.     BASEWIN

  119.     int     score;
  120.     int     level;
  121.     Tetrads nextTetrads;
  122. } InfoWin;

  123. void tetrisPrint(WINDOW *win, Point pos, Point block, char chr);

  124. void initGameWin(GameWin* _self)
  125. {
  126.     _self->win = newwin(GAMEWIN_YLEN + 2, _X(GAMEWIN_XLEN) + 1, GAMEWIN_Y, GAMEWIN_X);
  127.     box(_self->win, 0, 0);
  128.     mvwprintw(_self->win, 0, (_X(GAMEWIN_XLEN) + 2)/2 - 3, "TETRIS");
  129.     wrefresh(_self->win);

  130.     memset(_self->background, PIC_NULL, GAMEWIN_YLEN * GAMEWIN_XLEN);
  131.     memset(_self->matrix, PIC_NULL, GAMEWIN_YLEN * GAMEWIN_XLEN);

  132.     _self->pos = (Point){1, GAMEWIN_XLEN/2};
  133.     _self->level = 0;
  134. }

  135. void initInfoWin(InfoWin* _self)
  136. {
  137.     _self->win = newwin(INFOWIN_YLEN, _X(GAMEWIN_XLEN), INFOWIN_Y, INFOWIN_X);
  138.     box(_self->win, 0, 0);
  139.     mvwprintw(_self->win, 0, _X(GAMEWIN_XLEN)/2 - 2, "INFO");
  140.     mvwprintw(_self->win, 7, 2, "SCORE: 0");
  141.     mvwprintw(_self->win, 8, 2, "LEVEL: 0");
  142.     wrefresh(_self->win);

  143.     _self->score = 0;
  144.     _self->level = 0;
  145. }

  146. void showGameWin(GameWin* _self)
  147. {
  148.     int y = 0;
  149.     int x = 0;

  150.     for (y = 0; y < GAMEWIN_YLEN; ++y)
  151.         for (x = 0; x < GAMEWIN_XLEN; ++x)
  152.             tetrisPrint(_self->win, (Point){0, 0}, (Point){y, x}, (_self->background)[y][x]);

  153.     for (y = 0; y < GAMEWIN_YLEN; ++y)
  154.         for (x = 0; x < GAMEWIN_XLEN; ++x)
  155.             tetrisPrint(_self->win, (Point){0, 0}, (Point){y, x}, (_self->matrix)[y][x]);

  156.     for (x = 0; x < TETRADS_LEN; ++x)
  157.         tetrisPrint(_self->win, (Point){(_self->pos).y, (_self->pos).x}, (_self->curTetrads).blocks[x], PIC_BLOCK);

  158.     wrefresh(_self->win);
  159. }

  160. void showInfoWin(InfoWin* _self)
  161. {
  162.     int i = 0;
  163.    
  164.     mvwprintw(_self->win, 2, _X(INFOWIN_XLEN/2 - 2), "        ");
  165.     mvwprintw(_self->win, 3, _X(INFOWIN_XLEN/2 - 2), "        ");
  166.     mvwprintw(_self->win, 4, _X(INFOWIN_XLEN/2 - 2), "        ");
  167.     mvwprintw(_self->win, 5, _X(INFOWIN_XLEN/2 - 2), "        ");
  168.     mvwprintw(_self->win, 6, _X(INFOWIN_XLEN/2 - 2), "        ");

  169.     for (i = 0; i < TETRADS_LEN; ++i)
  170.         tetrisPrint(_self->win, (Point){2, INFOWIN_XLEN/2 - 2}, _self->nextTetrads.blocks[i], PIC_BLOCK);
  171.    
  172.     mvwprintw(_self->win, INFOWIN_YLEN - 3, 2, "SCORE: %d", _self->score);
  173.     mvwprintw(_self->win, INFOWIN_YLEN - 2, 2, "LEVEL: %d", _self->level);

  174.     wrefresh(_self->win);
  175. }
  176. /*** END   : 界面显示 ***/

  177. /*** 函数声明 ***/
  178. void newTetrads(Tetrads *tetrads);
  179. void initTetrads(Tetrads *tetrads);
  180. void spinTetrads(Tetrads *tetrads);
  181. int  runTetris(GameWin *gwin);
  182. int  checkBorder(GameWin *gwin);
  183. int  checkStop(GameWin *gwin);
  184. int  checkOver(GameWin *gwin);
  185. int  checkClean(GameWin *gwin);
  186. void refreshMatrix(GameWin *gwin);
  187. int  genRandom(int max);

  188. int main()
  189. {
  190.     /* init ncurses screen */
  191.     initscr();
  192.     raw();
  193.     noecho();
  194.     keypad(stdscr, TRUE);
  195.     curs_set(0);
  196.     refresh();

  197.     /* 初始化界面 */
  198.     GameWin *gwin;
  199.     InfoWin *iwin;

  200.     TETRISNEW(gwin, GameWin);
  201.     TETRISNEW(iwin, InfoWin);
  202.    
  203.     gwin->init(gwin);
  204.     iwin->init(iwin);

  205.     /* Tetris的处理使用简单的状态机实现 */
  206.     int f_end = 0;
  207.     int state = TETRIS_STATE_NEW;

  208.     newTetrads(&(iwin->nextTetrads));
  209.    
  210.     while (!f_end) {
  211.         switch (state) {
  212.         case TETRIS_STATE_NEW:
  213.             COPY_TETRADS(gwin->curTetrads, iwin->nextTetrads);
  214.             gwin->pos = (Point){1, 4};
  215.             newTetrads(&(iwin->nextTetrads));

  216.             iwin->show(iwin);
  217.             
  218.             state = TETRIS_STATE_MOVE;
  219.             break;
  220.         
  221.         case TETRIS_STATE_MOVE:
  222.             gwin->show(gwin);
  223.             
  224.             switch (runTetris(gwin)) {
  225.             case -1:
  226.                 goto END;
  227.                 break;
  228.             case 0:
  229.                 break;
  230.             case 1:
  231.                 state = TETRIS_STATE_STOP;
  232.                 break;
  233.             default:
  234.                 break;
  235.             }
  236.             
  237.             break;
  238.         
  239.         case TETRIS_STATE_STOP:
  240.             refreshMatrix(gwin);
  241.             iwin->score = checkClean(gwin);
  242.             state = TETRIS_STATE_NEW;
  243.             break;
  244.         
  245.         default :
  246.             f_end = 1;
  247.             break;
  248.         }
  249.     }

  250. END:
  251.     mvwprintw(gwin->win, GAMEWIN_YLEN/2 - 2, 5, "GAME OVER!!!");
  252.     mvwprintw(gwin->win, GAMEWIN_YLEN/2,     4, "Press any key");
  253.     mvwprintw(gwin->win, GAMEWIN_YLEN/2 + 1, 6, "to quit...");
  254.     wrefresh(gwin->win);
  255.    
  256.     getch();

  257.     TETRISDEL(iwin);
  258.     TETRISDEL(gwin);
  259.     endwin();
  260.    
  261.     return 0;
  262. }

  263. void tetrisPrint(WINDOW *win, Point pos, Point block, char chr)
  264. {
  265.     mvwaddch(win, pos.y + block.y + 1, (pos.x + block.x) * 2 + 1, chr);
  266. }

  267. void newTetrads(Tetrads *tetrads)
  268. {
  269.     tetrads->type = genRandom(TETRADS_MAX);
  270.    
  271.     initTetrads(tetrads);

  272.    
  273.     int spin = genRandom(DIR_MAX);
  274.     int i = 0;
  275.     for (; i <= spin; ++i) {
  276.         spinTetrads(tetrads);
  277.     }
  278. }

  279. void initTetrads(Tetrads *tetrads)
  280. {
  281.     switch (tetrads->type) {
  282.     case TETRADS_S:
  283.         tetrads->blocks[0] = (Point){2, 0};
  284.         tetrads->blocks[1] = (Point){2, 1};
  285.         tetrads->blocks[2] = (Point){1, 1};
  286.         tetrads->blocks[3] = (Point){1, 2};
  287.         break;

  288.     case TETRADS_Z:
  289.         tetrads->blocks[0] = (Point){1, 0};
  290.         tetrads->blocks[1] = (Point){1, 1};
  291.         tetrads->blocks[2] = (Point){2, 1};
  292.         tetrads->blocks[3] = (Point){2, 2};
  293.         break;

  294.     case TETRADS_L:
  295.         tetrads->blocks[0] = (Point){2, 0};
  296.         tetrads->blocks[1] = (Point){2, 1};
  297.         tetrads->blocks[2] = (Point){1, 1};
  298.         tetrads->blocks[3] = (Point){0, 1};
  299.         break;

  300.     case TETRADS_J:
  301.         tetrads->blocks[0] = (Point){0, 0};
  302.         tetrads->blocks[1] = (Point){1, 0};
  303.         tetrads->blocks[2] = (Point){1, 1};
  304.         tetrads->blocks[3] = (Point){1, 2};
  305.         break;

  306.     case TETRADS_O:
  307.         tetrads->blocks[0] = (Point){0, 0};
  308.         tetrads->blocks[1] = (Point){0, 1};
  309.         tetrads->blocks[2] = (Point){1, 0};
  310.         tetrads->blocks[3] = (Point){1, 1};
  311.         break;

  312.     case TETRADS_T:
  313.         tetrads->blocks[0] = (Point){0, 1};
  314.         tetrads->blocks[1] = (Point){1, 0};
  315.         tetrads->blocks[2] = (Point){1, 1};
  316.         tetrads->blocks[3] = (Point){1, 2};
  317.         break;

  318.     case TETRADS_I:
  319.         tetrads->blocks[0] = (Point){0, 1};
  320.         tetrads->blocks[1] = (Point){1, 1};
  321.         tetrads->blocks[2] = (Point){2, 1};
  322.         tetrads->blocks[3] = (Point){3, 1};
  323.         break;

  324.     default:
  325.         break;
  326.     }
  327. }

  328. /**
  329. * 旋转Tetrads
  330. */
  331. void spinTetrads(Tetrads *tetrads)
  332. {
  333.     int i = 0;
  334.    
  335.     switch (tetrads->type) {
  336.     case TETRADS_O:
  337.         break;

  338.     case TETRADS_I:
  339.         /* x,y互换 */
  340.         for (i = 0; i < TETRADS_LEN; ++i)
  341.             EXCHANGE_XY(tetrads->blocks[i]);
  342.         break;

  343.     default:
  344.         for (i = 0; i < TETRADS_LEN; ++i)
  345.             EXCHANGE_XY(tetrads->blocks[i]);

  346.         for (i = 0; i < TETRADS_LEN; ++i)
  347.             EXCHANGE_2Y(tetrads->blocks[i]);

  348.         break;
  349.     }
  350. }

  351. /**
  352. * Return:
  353. *   -1    game over
  354. *    0    continue
  355. *    1    stop
  356. */
  357. int runTetris(GameWin *gwin)
  358. {
  359.     int ret = 0;

  360.     fd_set fset;
  361.    
  362.     FD_ZERO(&fset);
  363.     FD_SET(0, &fset);
  364.    
  365.     struct timeval timeout;
  366.     timeout.tv_sec  = 0;
  367.     timeout.tv_usec = 500000 - 10000 * gwin->level;
  368.    
  369.     int fd = -1;
  370.     if ((fd = select(1, &fset, NULL, NULL, &timeout)) <= 0) {
  371.         ++((gwin->pos).y);
  372.         while (checkStop(gwin) != 0) {
  373.             --((gwin->pos).y);
  374.             ret = 1;
  375.         }

  376.         if (ret == 1) {
  377.             if (checkOver(gwin))
  378.                 return -1;

  379.             return 1;
  380.         }

  381.         return 0;
  382.     }

  383.     Tetrads tmptetrads;
  384.     char ch;
  385.     int  n = 0;
  386.     switch (ch = getch()) {
  387.     case 'w':
  388.         COPY_TETRADS(tmptetrads, gwin->curTetrads);
  389.         spinTetrads(&gwin->curTetrads);

  390.         while ((n = checkBorder(gwin)) != 0)
  391.             (gwin->pos).x += n;

  392.         while (checkStop(gwin) != 0) {
  393.             --((gwin->pos).y);
  394.             ret = 1;
  395.         }

  396.         return ret;

  397.     case 's':
  398.         ++((gwin->pos).y);
  399.         while (checkStop(gwin) != 0) {
  400.             --((gwin->pos).y);
  401.             ret = 1;
  402.         }

  403.         if (ret == 1) {
  404.             if (checkOver(gwin))
  405.                 return -1;

  406.             return 1;
  407.         }

  408.         return 0;

  409.     case 'a':
  410.         --((gwin->pos).x);
  411.         while ((n = checkBorder(gwin)) != 0)
  412.             (gwin->pos).x += n;
  413.         break;

  414.     case 'd':
  415.         ++((gwin->pos).x);
  416.         while ((n = checkBorder(gwin)) != 0)
  417.             (gwin->pos).x += n;
  418.         break;

  419.     default:
  420.         break;
  421.     }

  422.     return 0;
  423. }

  424. /**
  425. * 检查是否达到边线
  426. */
  427. int checkBorder(GameWin *gwin)
  428. {
  429.     int i = 0;
  430.     int n = 0;
  431.     for (i = 0; i < TETRADS_LEN; ++i) {
  432.         if ((n = ((gwin->pos).x + (gwin->curTetrads).blocks[i].x)) < 0)
  433.             return -n;

  434.         if ((n = ((gwin->pos).x + (gwin->curTetrads).blocks[i].x)) > GAMEWIN_XLEN - 1)
  435.             return GAMEWIN_XLEN - 1 - n;
  436.     }

  437.     return 0;
  438. }

  439. /**
  440. * 检查是否停止
  441. */
  442. int checkStop(GameWin *gwin)
  443. {
  444.     int i = 0;
  445.     for (i = 0; i < TETRADS_LEN; ++i)
  446.         if (gwin->matrix[(gwin->pos).y + (gwin->curTetrads).blocks[i].y][(gwin->pos).x + (gwin->curTetrads).blocks[i].x] == PIC_BLOCK
  447.             || ((gwin->pos).y + (gwin->curTetrads).blocks[i].y) >= GAMEWIN_YLEN)
  448.             return 1;

  449.     return 0;
  450. }

  451. /**
  452. * 检查是否游戏结束
  453. */
  454. int checkOver(GameWin *gwin)
  455. {
  456.     int i = 0;
  457.     for (i = 0; i < TETRADS_LEN; ++i)
  458.         if ((gwin->pos).y <= 0)
  459.             return 1;

  460.     return 0;
  461. }

  462. /**
  463. * 检查是否需要清楚一行
  464. */
  465. int checkClean(GameWin *gwin)
  466. {
  467.     char bline[GAMEWIN_XLEN];
  468.     memset(bline, PIC_BLOCK, GAMEWIN_XLEN);
  469.    
  470.     int i     = 0;
  471.     int num   = 0;
  472.     int score = 0;
  473.     for (i = 0; i < TETRADS_LEN; ++i) {
  474.         num = (gwin->pos).y + (gwin->curTetrads).blocks[i].y;
  475.         if (strncmp(gwin->matrix[num], bline, GAMEWIN_XLEN) == 0) {
  476.             score += 10;
  477.             for (; num > 0; --num)
  478.                 memcpy(gwin->matrix[num], gwin->matrix[num-1], GAMEWIN_XLEN);
  479.         }
  480.     }
  481.    
  482.     return score;
  483. }

  484. void refreshMatrix(GameWin *gwin)
  485. {
  486.     int i = 0;
  487.     for (i = 0; i < TETRADS_LEN; ++i)
  488.         gwin->matrix[(gwin->pos).y + (gwin->curTetrads).blocks[i].y][(gwin->pos).x + (gwin->curTetrads).blocks[i].x] = PIC_BLOCK;
  489. }

  490. /**
  491. * 返回0~max-1的一个随机数
  492. */
  493. int genRandom(int max)
  494. {
  495.     srandom((int)time(NULL));
  496.     return (random() % max);
  497. }
复制代码

作者: dave_cn   发布时间: 2010-07-28

不错,支持。

不过用printf也可以的

作者: okocha-jay   发布时间: 2010-07-28

热门下载

更多