免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 2839 | 回复: 13
打印 上一主题 下一主题

[原创]linux下面的打小球游戏 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-03-21 11:38 |只看该作者 |倒序浏览
linux下面的C编程,我还是新手,请大家别笑话。


  1. /*
  2. * Brick & Ball
  3. * by Jerry Fleming <jerryfleming2006@gmail.com>
  4. *
  5. * This is a small game inspired from similar one in Motorola Mobile C289,
  6. * and my first REAL program in C :) Please tell me if you have a better
  7. * implementation or any suggestions.
  8. *
  9. * HISTORY:
  10. * 2006-10-25: third (current) version with c language
  11. * 2006-10-01: second version with tkinter
  12. * 2006-04-19: first version with curses
  13. *
  14. * TODO:
  15. * Nothing to do right now. :) If you have any ideas to improve or enhance it,
  16. * please contact me.
  17. */

  18. #include <stdio.h>
  19. #include <string.h>
  20. #include <ncurses.h>
  21. #include <stdlib.h>          /* for exit(), rand(), abs() */
  22. #include <stddef.h>          /* for NULL */
  23. #include <unistd.h>          /* for sleep() */
  24. #include <signal.h>          /* for SIGWINCH */
  25. #include <assert.h>          /* for DEBUG */

  26. #define NORMAL 1             /* game status */
  27. #define PAUSE  2
  28. #define OVER   3
  29. #define QUIT   4

  30. #define BLOCK  1             /* color pairs */
  31. #define TXT    2
  32. #define BAR    3
  33. #define BALL   4
  34. #define CLEAR  5

  35. /*
  36. * globals
  37. */
  38. int speed = 10;
  39. int cnt = 0;                 /* bricks yet remain on board */
  40. int score = 0;
  41. int level = 0;
  42. int width = 40;
  43. int height = 50;             /* for the board */
  44. short state = NORMAL;        /* see define */
  45. char *statestr = "Normal";   /* additional str to explain the game status */
  46. const int bw = 7;            /* brick width */
  47. const char brick[] = "       ";
  48. int bricks[100][3];
  49. int pad;
  50. int ball[2];
  51. int dir[2] = { 1, -1 };
  52. int ch = 0;                  /* user command */

  53. /*
  54. * text strings {{{
  55. */
  56. const char *tStart[] = {
  57.     "  ______        _       _         ___      ______        _ _         ",
  58.     " (____  \\      (_)     | |       / _ \\    (____  \\      | | |        ",
  59.     "  ____)  ) ____ _  ____| |  _   ( (_) )    ____)  )_____| | |        ",
  60.     " |  __  ( / ___) |/ ___) |_/ )   ) _ (    |  __  ((____ | | |        ",
  61.     " | |__)  ) |   | ( (___|  _ (   ( (/  \\   | |__)  ) ___ | | |        ",
  62.     " |______/|_|   |_|\\____)_| \\_)   \\__/\\_)  |______/\\_____|\\_)_)       ",
  63.     "                                                                     ",
  64.     "                                                                     ",
  65.     "                                                                     ",
  66.     "       by Jerry Fleming <jerryfleming2006@gmail.com>                 ",
  67.     "                                                                     ",
  68.     "                                                                     ",
  69.     "        GAME STARTING! PRESS ANY KEY TO GO ON ...                    ",
  70.     "                                                                     ",
  71.     " ------------------------------------------------------------        ",
  72.     "| P: Pause / Resume  <-, ->: Move Right / Left  Y:Yes  N: No |       ",
  73.     " ------------------------------------------------------------        ",
  74.     ""
  75. };

  76. const char *tExit[] = {
  77.     "                                               88888                         88888",
  78.     "88888888888             88       ad88888ba     88 8b        d8      d8          88",
  79.     "88                      \"\"   ,d d8\"     \"8b    88  Y8,    ,8P     ,8P'          88",
  80.     "88                           88 \"\"      a8P    88   Y8,  ,8P     d8\"            88",
  81.     "88aaaaa     8b,     ,d8 88 MM88MMM   ,a8P\"     88    \"8aa8\"    ,8P' 8b,dPPYba,  88",
  82.     "88\"\"\"\"\"      `Y8, ,8P'  88   88     d8\"        88     `88'    d8\"   88P'   `\"8a 88",
  83.     "88             )888(    88   88     \"\"         88      88   ,8P'    88       88 88",
  84.     "88           ,d8\" \"8b,  88   88,    aa         88      88  d8\"      88       88 88",
  85.     "88888888888 8P'     `Y8 88   \"Y888  88         88      88 8P'       88       88 88",
  86.     "                                               88888                         88888",
  87.     ""
  88. };

  89. const char *tOver[] = {
  90.     "  ,ad8888ba,                                                                                            88",
  91.     " d8\"'    `\"8b                                                                                           88",
  92.     "d8'                                                                                                     88",
  93.     "88            ,adPPYYba, 88,dPYba,,adPYba,   ,adPPYba,     ,adPPYba,  8b       d8  ,adPPYba, 8b,dPPYba, 88",
  94.     "88      88888 \"\"     `Y8 88P'   \"88\"    \"8a a8P_____88    a8\"     \"8a `8b     d8' a8P_____88 88P'   \"Y8 88",
  95.     "Y8,        88 ,adPPPPP88 88      88      88 8PP\"\"\"\"\"\"\"    8b       d8  `8b   d8'  8PP\"\"\"\"\"\"\" 88         \"\"",
  96.     " Y8a.    .a88 88,    ,88 88      88      88 \"8b,   ,aa    \"8a,   ,a8\"   `8b,d8'   \"8b,   ,aa 88         aa",
  97.     "  `\"Y88888P\"  `\"8bbdP\"Y8 88      88      88  `\"Ybbd8\"'     `\"YbbdP\"'      \"8\"      `\"Ybbd8\"' 88         88",
  98.     ""
  99. };

  100. const char *tGoon[] = {
  101.     "                                                                88888                         88888",
  102.     "  ,ad8888ba,                                      ad88888ba     88 8b        d8      d8          88",
  103.     " d8\"'    `\"8b                                    d8\"     \"8b    88  Y8,    ,8P     ,8P'          88",
  104.     "d8'                                              \"\"      a8P    88   Y8,  ,8P     d8\"            88",
  105.     "88             ,adPPYba,      ,adPPYba,  8b,dPPYba,   ,a8P\"     88    \"8aa8\"    ,8P' 8b,dPPYba,  88",
  106.     "88      88888 a8\"     \"8a    a8\"     \"8a 88P'   `\"8a d8\"        88     `88'    d8\"   88P'   `\"8a 88",
  107.     "Y8,        88 8b       d8    8b       d8 88       88 \"\"         88      88   ,8P'    88       88 88",
  108.     " Y8a.    .a88 \"8a,   ,a8\"    \"8a,   ,a8\" 88       88 aa         88      88  d8\"      88       88 88",
  109.     "  `\"Y88888P\"   `\"YbbdP\"'      `\"YbbdP\"'  88       88 88         88      88 8P'       88       88 88",
  110.     "                                                                88888                         88888",
  111.     ""
  112. };

  113. const char *tHelp =
  114.     "Use left and right arrow keys to move the pad and bounce the ball so that it won't hit the ground. Hit the brick and score.";
  115. /*
  116. * string variables }}}
  117. */

  118. /*
  119. * change sceen size, exit if too small
  120. */
  121. void resizescr(int sig)
  122. {
  123.     statestr = "Quit because screen resized.";
  124.     state = QUIT;
  125. }                            /* resizescr()  */

  126. /*
  127. * print msg on center of screen
  128. * y_n_key: exit on pressing Y or N (key is true) or any char (key false)
  129. * clearmsg: clear the msg window (when 1, or 2 and Y, or 3 and N)
  130. */
  131. bool print_msg(const char *msg[], const bool y_n_key, const int clearmsg)
  132. {
  133.     WINDOW *txtwin = NULL;
  134.     int length = 0;
  135.     int tmplength = 0;
  136.     int line = 0;
  137.     int i;
  138.     int left;
  139.     int top;
  140.     char emptymsg[width];

  141.     for (;;) {
  142.         tmplength = strlen(msg[line]);
  143.         if (tmplength == 0)
  144.             break;
  145.         if (length < tmplength)
  146.             length = tmplength;
  147.         line++;
  148.     }
  149.     assert(length < width);
  150.     assert(line != 0);
  151.     top = (height - line) / 2;
  152.     left = (width - length) / 2;
  153.     txtwin = newwin(line, length, top, left);
  154.     wattrset(txtwin, COLOR_PAIR(TXT));
  155.     assert(txtwin != NULL);
  156.     for (i = 0; i < line; i++) {
  157.         mvwaddstr(txtwin, i, 0, msg[i]);
  158.     }
  159.     wrefresh(txtwin);

  160.     timeout(3000);
  161.     for (;;) {
  162.         ch = getch();
  163.         if (y_n_key)
  164.             break;
  165.         else {
  166.             if (ch == ERR || ch == 'y' || ch == 'Y') {
  167.                 ch = 'Y';
  168.                 break;
  169.             }
  170.             if (ch == 'n' || ch == 'N') {
  171.                 ch = 'N';
  172.                 break;
  173.             }
  174.         }
  175.     }

  176.     if (clearmsg == 1
  177.         || (clearmsg == 2 && ch == 'Y')
  178.         || (clearmsg == 3 && ch == 'N')
  179.     ) {
  180.         for (i = 0; i < length; i++)
  181.             emptymsg[i] = ' ';
  182.         wattrset(txtwin, COLOR_PAIR(TXT));
  183.         for (i = 0; i < line; i++) {
  184.             mvwaddstr(txtwin, i, 0, emptymsg);
  185.         }
  186.         wrefresh(txtwin);
  187.         delwin(txtwin);
  188.     }
  189.     i = ch, ch = 0;          /* clear input for later use */
  190.     timeout(100);

  191.     if (i == 'N')
  192.         return FALSE;
  193.     return TRUE;
  194. }                            /* print_msg()  */

  195. /*
  196. * draw pad, ball, bricks, and bar together
  197. */
  198. void draw_board(void)
  199. {
  200.     int i, j;
  201.     char barstr[width];

  202.     level++;
  203.     cnt = 0;
  204.     dir[0] = 1, dir[1] = -1;

  205.     /* brick */
  206.     i = width % (bw + 1) / 2;   /* width -1 + gap */
  207.     j = 1;
  208.     attrset(COLOR_PAIR(BLOCK));
  209.     for (;;) {
  210.         mvaddstr(j, i, brick);
  211.         bricks[cnt][0] = i;
  212.         bricks[cnt][1] = j;
  213.         bricks[cnt][2] = 1;
  214.         i = i + bw + 1;
  215.         cnt++;
  216.         if (i >= width - bw) {
  217.             if (cnt > 50)
  218.                 break;
  219.             i = width % (bw + 1) / 2;
  220.             j += 2;
  221.         }
  222.     }
  223.     bricks[cnt][2] = -1;     /* mark the end or all bricks */

  224.     if (level == 1) {
  225.         /* pad */
  226.         attrset(COLOR_PAIR(BLOCK));
  227.         pad = rand() % (width - bw - 1);
  228.         mvaddstr(height - 2, pad, brick);

  229.         /* bar */
  230.         for (i = 0; i < width; i++)
  231.             barstr[i] = ' ';
  232.         attrset(COLOR_PAIR(BAR));
  233.         mvaddstr(height - 1, 0, barstr);
  234.         mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score,
  235.                  level, statestr);
  236.     }

  237.     /* ball */
  238.     attrset(COLOR_PAIR(BALL));
  239.     ball[0] = pad, ball[1] = height - 3;
  240.     while (abs(ball[0] - pad) < 15)
  241.         ball[0] = rand() % (width - bw - 1);
  242.     mvaddstr(ball[1], ball[0], " ");

  243.     refresh();
  244. }                            /* draw_board()  */

  245. /*
  246. * try to stop game
  247. */
  248. void quit_game(const int ch)
  249. {
  250.     if (ch == 'q') {
  251.         if (cnt < 0          /* do not want another level */
  252.             || (cnt > 0 && print_msg(tExit, FALSE, 3))  /* really meant to
  253.                                                          * exit */
  254.         ) {
  255.             state = QUIT;
  256.             statestr = "Quit game";
  257.         }
  258.     } else if (ch == 'o') {
  259.         state = OVER;
  260.         statestr = "Game over";
  261.         print_msg(tOver, TRUE, 0);
  262.     } else if (state == PAUSE) {
  263.         state = NORMAL;
  264.         statestr = "Normal";
  265.     } else {
  266.         state = PAUSE;
  267.         statestr = "Pause";
  268.     }
  269.     /* bar */
  270.     attrset(A_NORMAL | COLOR_PAIR(BAR));
  271.     mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score, level,
  272.              statestr);
  273.     refresh();
  274. }                            /* quit_game()  */

  275. /*
  276. * move the ball forward, turn if necessary, add scores, and quite if hit ground
  277. */
  278. void move_ball()
  279. {
  280.     int i;
  281.     int tmpball[] = { ball[0], ball[1] };

  282.     if (state != NORMAL)
  283.         return;

  284.     /* ball */
  285.     attrset(A_REVERSE | COLOR_PAIR(BALL));
  286.     mvaddstr(ball[1], ball[0], " ");
  287.     /* restore pad after hit */
  288.     attrset(A_NORMAL | COLOR_PAIR(BLOCK));
  289.     mvaddstr(height - 2, pad, brick);
  290.     tmpball[0] += dir[0], tmpball[1] += dir[1];

  291.     /* change direction */
  292.     if (tmpball[1] < 0)
  293.         dir[1] = -dir[1];
  294.     if (tmpball[0] < 0 || tmpball[0] > width)
  295.         dir[0] = -dir[0];

  296.     /* hit bricks */
  297.     attrset(A_REVERSE | COLOR_PAIR(BLOCK));
  298.     for (i = 0;; i++) {
  299.         if (bricks[i][2] == -1)
  300.             break;
  301.         if (bricks[i][2] == 0)
  302.             continue;
  303.         if (bricks[i][0] <= tmpball[0]
  304.             && bricks[i][0] + bw >= tmpball[0]
  305.             && bricks[i][1] == tmpball[1]
  306.         ) {
  307.             bricks[i][2] = 0;
  308.             /*
  309.              * tricky: make sure the direction is top-down
  310.              */
  311.             dir[1] = abs(dir[1]);
  312.             score += 10;
  313.             cnt--;
  314.             refresh();
  315.             mvaddstr(bricks[i][1], bricks[i][0], brick);
  316.             if (cnt <= 0) {  /* another level */
  317.                 if (print_msg(tGoon, FALSE, 2)) {
  318.                     draw_board();
  319.                 } else {
  320.                     quit_game('q');
  321.                 }
  322.             }
  323.         }
  324.     }

  325.     /* hit pad */
  326.     if (tmpball[1] == height - 2) {
  327.         if (tmpball[0] < pad || tmpball[0] > pad + bw)
  328.             quit_game('o');
  329.         /*
  330.          * for some reason, the ball may enter the pad, and change dir will not
  331.          * get it out, so use abs() to turn back
  332.          */
  333.         dir[1] = -abs(dir[1]);
  334.         if (tmpball[0] == pad || tmpball[0] == pad + bw) {  /* on both ends */
  335.             dir[0] = -dir[0];
  336.         }
  337.     }

  338.     /* bar */
  339.     attrset(A_NORMAL | COLOR_PAIR(BAR));
  340.     mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score, level,
  341.              statestr);

  342.     ball[0] += dir[0], ball[1] += dir[1];
  343.     attrset(A_NORMAL | COLOR_PAIR(BALL));
  344.     mvaddstr(ball[1], ball[0], " ");
  345.     refresh();
  346. }                            /* move_ball()  */

  347. /*
  348. * move pad to left or right according to command
  349. */
  350. int move_pad(const int ch)
  351. {
  352.     int move = 0;

  353.     switch (ch) {
  354.         case KEY_LEFT:
  355.             move = -2;
  356.             break;
  357.         case KEY_RIGHT:
  358.             move = 2;
  359.             break;
  360.         case 'q':
  361.             quit_game(ch);
  362.             break;
  363.         case 'p':
  364.             quit_game(ch);
  365.             break;
  366.         default:
  367.             return 0;
  368.     }
  369.     attrset(A_REVERSE | COLOR_PAIR(BLOCK));
  370.     mvaddstr(height - 2, pad, brick);
  371.     pad = pad + move;
  372.     if (pad < 0)
  373.         pad = 0;
  374.     if (pad > width - bw)
  375.         pad = width - bw;
  376.     attrset(A_NORMAL | COLOR_PAIR(BLOCK));
  377.     mvaddstr(height - 2, pad, brick);

  378.     refresh();
  379.     return 0;
  380. }                            /* move_pad()  */

  381. /*
  382. * main
  383. */
  384. int main(void)
  385. {
  386.     initscr();
  387.     start_color();
  388.     init_pair(BLOCK, COLOR_BLACK, COLOR_RED);   /* for bricks and pad */
  389.     init_pair(TXT, COLOR_CYAN, COLOR_BLACK);    /* for text strings */
  390.     init_pair(BAR, COLOR_WHITE, COLOR_BLUE);    /* for bar */
  391.     init_pair(BALL, COLOR_BLACK, COLOR_WHITE);  /* for ball */
  392.     noecho();
  393.     raw();                   /* disable line buffering */
  394.     timeout(100);
  395.     cbreak();
  396.     keypad(stdscr, TRUE);
  397.     curs_set(0);
  398.     getmaxyx(stdscr, height, width);
  399.     signal(SIGWINCH, resizescr);

  400.     if (height >= 20 && width >= 80) {
  401.         refresh();
  402.         print_msg(tStart, TRUE, 0);
  403.         clear();
  404.         draw_board();
  405.         for (;;) {
  406.             ch = getch();
  407.             move_ball();
  408.             if (ch != ERR)
  409.                 move_pad(ch);
  410.             if (state == OVER || state == QUIT)
  411.                 break;
  412.         }
  413.     } else {                 /* screen too small, exit with complaint */
  414.         state = QUIT;
  415.         statestr = "Screen too small. Game aborted.";
  416.     }
  417.     sleep(1), flash();
  418.     sleep(1), flash();
  419.     curs_set(1);
  420.     keypad(stdscr, FALSE);
  421.     nocbreak();
  422.     notimeout(stdscr, TRUE);
  423.     noraw();
  424.     echo();
  425.     endwin();
  426.     puts(statestr);
  427.     exit(0);
  428. }                            /* main()  */

  429. /*
  430. * Local variables:
  431. * tab-width: 4
  432. * indent-tabs-mode: nil
  433. * c-basic-offset: 4
  434. * End:
  435. * vim: tw=80:sw=4:sts=4:fdm=marker
  436. */
复制代码


编译:

  1. gcc -Wall -pedantic --std=c99 -g -o game game.c -lncurses
复制代码

论坛徽章:
0
2 [报告]
发表于 2007-03-21 12:11 |只看该作者
请教一个问题:比如

1111
      1111

这样的动画你怎么完成的????

论坛徽章:
0
3 [报告]
发表于 2007-03-21 13:04 |只看该作者
我还没有搞懂你什么意思?是1不停的移动位置吗?

论坛徽章:
0
4 [报告]
发表于 2007-03-21 13:28 |只看该作者
玩了一下,下面负责接的那块挡板跑的越快,小球也就跑的越快,不知道这个是楼主故意留的还是bug?

论坛徽章:
0
5 [报告]
发表于 2007-03-21 14:05 |只看该作者
原帖由 jerryfleming 于 2007-3-21 13:04 发表
我还没有搞懂你什么意思?是1不停的移动位置吗?

是的。你是怎么搞的?

论坛徽章:
0
6 [报告]
发表于 2007-03-21 15:04 |只看该作者
原帖由 cugb_cat 于 2007-3-21 13:28 发表
玩了一下,下面负责接的那块挡板跑的越快,小球也就跑的越快,不知道这个是楼主故意留的还是bug?

不是故意的,也不是bug。
用户按键和小球的运动应该在两个线程里面进行(小球要不停运动,同时还要检测是否有用户按键)。我为了简单,把它们放在一个线程里面。


  1. for (;;) {
  2.             ch = getch();
  3.             move_ball();
  4.             if (ch != ERR)
  5.                 move_pad(ch);
  6.             if (state == OVER || state == QUIT)
  7.                 break;
  8.         }
复制代码

从代码可以看出,小球跑得越快,按键时挡板的反应就越快。在这个无限循环中,小球的速度受到计算机系统本身的制约,而不是由挡板的快慢决定的。

你只看到了现象,把原因和结果颠倒了。

[ 本帖最后由 jerryfleming 于 2007-3-21 15:10 编辑 ]

论坛徽章:
0
7 [报告]
发表于 2007-03-21 15:05 |只看该作者
原帖由 中国大表哥 于 2007-3-21 14:05 发表

是的。你是怎么搞的?

这很简单。把原来位置的去掉,在新的位置写上。

论坛徽章:
0
8 [报告]
发表于 2007-03-21 15:24 |只看该作者
原帖由 jerryfleming 于 2007-3-21 15:05 发表

这很简单。把原来位置的去掉,在新的位置写上。

你有没有QQ或者MSN???

论坛徽章:
0
9 [报告]
发表于 2007-03-21 15:26 |只看该作者
道理我明白但是,用C语言怎么写????

论坛徽章:
0
10 [报告]
发表于 2007-03-21 16:13 |只看该作者

回复 8楼 中国大表哥 的帖子

我的MSN:jerry.fleming@saybot.com
QQ 34302194
好像资料里面有啊
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP