⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ball.c

📁 打小球游戏C语言源代码
💻 C
字号:
 /*
  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  */
 
 #include <stdio.h>
 #include <string.h>
 #include <ncurses.h>
 #include <stdlib.h>          /* for exit(), rand(), abs() */
 
 #include <stddef.h>          /* for NULL */
 #include <time.h>            /* for sleep() */
 #include <signal.h>          /* for SIGWINCH */
 
 #define NORMAL 1             /* status of game */
 #define PAUSE  2
 #define OVER   3
 #define QUIT   4
 #define BLOCK  1             /* color pairs */
 #define TXT    2
 #define BAR    3
 #define BALL   4
 #define CLEAR  5
 
 extern unsigned int sleep(unsigned int seconds);
 
 /*
  * globals 
  */
 int speed = 10;
 int cnt = 0;                 /* bricks yet remain on board */
 int score = 0;
 int level = 0;
 int width = 40;
 int height = 50;             /* for the board */
 short state = NORMAL;        /* see define */
 char *statestr = "Normal";   /* additional str to explain the game status */
 const int bw = 7;            /* brick width */
 const char brick[] = "       ";
 int bricks[100][3];
 int pad;
 int ball[2];
 int dir[2] = { 1, -1 };
 int ch = 0;                  /* user command */
 
 /*
 +-- 62 lines: * text strings -------------------------------------------------------------------------------------------------------------
  */
 
 /*
  * change sceen size, exit if too small 
  */
 void resizescr(int sig)
 {
     statestr = "Screen resized.";
     getmaxyx(stdscr, height, width);
 }                            /* resizescr()  */
 
 /*
  * print msg on center of screen, exit on pressing Y or N (key is true) or any
  * char (key false)
  */
 bool print_msg(char *msg, bool y_n_key, bool clearmsg)
 {
     char *rest;
     char *str[30];
     char emptystr[width];
     int line = 0;
     int i;
     int length;
     int left;
     int top;
     char delimiters[] = "\n";
 
     length = strlen(str[line] = strtok(msg, delimiters));
     while ((rest = strtok(NULL, delimiters)) != NULL) {
         line++;
         if (length < strlen(rest))
             length = strlen(rest);
         str[line] = rest;
     }
 
     top = (height - line) / 2;
     left = (width - length) / 2;
     attrset(COLOR_PAIR(TXT));
     for (i = 0; i <= line; i++) {
         mvprintw(top++, left, "%s", str[i]);
     }
     refresh();
 
     timeout(3000);
     for (;;) {
         ch = getch();
         if (y_n_key)
             break;
         else {
             if (ch == ERR || ch == 'y' || ch == 'Y') {
                 ch = 'Y';
                 break;
             }
             if (ch == 'n' || ch == 'N') {
                 ch = 'N';
                 break;
             }
         }
     }
 
     if (clearmsg) {
         top = (height - line) / 2;
         attrset(COLOR_PAIR(CLEAR));
         for (i = 0; i < width; i++)
             emptystr[i] = ' ';
         for (i = 0; i <= line; i++) {
             mvaddstr(top++, 0, emptystr);
         }
         refresh();
     }
     i = ch, ch = 0;          /* clear input for later use */
     timeout(100);
 
     if (i == 'N')
         return FALSE;
     return TRUE;
 }                            /* print_msg()  */
 
 /*
  * draw pad, ball, bricks, and bar together 
  */
 void draw_board(void)
 {
     int i, j;
     char barstr[width];
 
     level++;
     cnt = 0;
     dir[0] = 1, dir[1] = -1;
 
     /* brick */
     i = width % (bw + 1) / 2;   /* width -1 + gap */
     j = 1;
     attrset(COLOR_PAIR(BLOCK));
     for (;;) {
         mvaddstr(j, i, brick);
         bricks[cnt][0] = i;
         bricks[cnt][1] = j;
         bricks[cnt][2] = 1;
         i = i + bw + 1;
         cnt++;
         if (i >= width - bw) {
             if (cnt > 50)
                 break;
             i = width % (bw + 1) / 2;
             j += 2;
         }
     }
     bricks[cnt][2] = -1;     /* mark the end or all bricks */
 
     if (level == 1) {
         /* pad */
         attrset(COLOR_PAIR(BLOCK));
         pad = rand() % (width - bw - 1);
         mvaddstr(height - 2, pad, brick);
 
         /* bar */
         for (i = 0; i < width; i++)
             barstr[i] = ' ';
         attrset(COLOR_PAIR(BAR));
         mvaddstr(height - 1, 0, barstr);
         mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score,
                  level, statestr);
     }
 
     /* ball */
     attrset(COLOR_PAIR(BALL));
     ball[0] = pad, ball[1] = height - 3;
     while (abs(ball[0] - pad) < 15)
         ball[0] = rand() % (width - bw - 1);
     mvaddstr(ball[1], ball[0], " ");
 
     refresh();
 }                            /* draw_board()  */
 
 /*
  * try to stop game 
  */
 void quit_game(const int ch)
 {
     if (ch == 'q') {
         if (cnt < 0          /* do not want another level */
             || (cnt > 0 && print_msg(tExit, FALSE, TRUE))   /* really meant to
                                                              * exit */
             ) {
             state = QUIT;
             statestr = "Quit game";
         }
     } else if (ch == 'o') {
         state = OVER;
         statestr = "Game over";
         print_msg(tOver, TRUE, FALSE);
     } else if (state == PAUSE) {
         state = NORMAL;
         statestr = "Normal";
     } else {
         state = PAUSE;
         statestr = "Pause";
     }
     /* bar */
     attrset(A_NORMAL | COLOR_PAIR(BAR));
     mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score, level,
              statestr);
     refresh();
 }                            /* quit_game()  */
 
 /*
  * move the ball forward, turn if necessary, add scores, and quite if hit ground
  */
 void move_ball()
 {
     int i;
 
     if (state != NORMAL)
         return;
 
     /* ball */
     attrset(A_REVERSE | COLOR_PAIR(BALL));
     mvaddstr(ball[1], ball[0], " ");
     /* restore pad after hit */
     attrset(A_NORMAL | COLOR_PAIR(BLOCK));
     mvaddstr(height - 2, pad, brick);
     ball[0] += dir[0], ball[1] += dir[1];
     attrset(A_NORMAL | COLOR_PAIR(BALL));
     mvaddstr(ball[1], ball[0], " ");
 
     /* change direction */
     if (ball[1] < 0)
         dir[1] = -dir[1];
     if (ball[0] < 0 || ball[0] > width)
         dir[0] = -dir[0];
 
     /* hit bricks */
     attrset(A_REVERSE | COLOR_PAIR(BLOCK));
     for (i = 0;; i++) {
         if (bricks[i][2] == -1)
             break;
         if (bricks[i][2] == 0)
             continue;
         if (bricks[i][0] <= ball[0]
             && bricks[i][0] + bw >= ball[0]
             && bricks[i][1] == ball[1]
             ) {
             bricks[i][2] = 0;
             /*
              * tricky: make sure the direction is top-down
              */
             dir[1] = abs(dir[1]);
             score += 10;
             cnt--;
             refresh();
             mvaddstr(bricks[i][1], bricks[i][0], brick);
            if (cnt <= 0) {  /* another level */
                 if (print_msg(tGoon, FALSE, TRUE)) {
                    draw_board();
                 } else {
                    quit_game('q');
                 }
             }
         }
     }
 
     /* hit pad */
     if (ball[1] == height - 2) {
         if (ball[0] < pad || ball[0] > pad + bw)
             quit_game('o');
         /*
          * for some reason, the ball may enter the pad, and change dir will not
          * get it out, so use abs() to turn back
          */
         dir[1] = -abs(dir[1]);
         if (ball[0] == pad || ball[0] == pad + bw) {    /* on both ends */
             dir[0] = -dir[0];
         }
    }
 
     /* bar */
     attrset(A_NORMAL | COLOR_PAIR(BAR));
     mvprintw(height - 1, 0, "SCORE: %03d  LEVEL: %d  STATE: %-9s", score, level,
              statestr);
     refresh();
 }                            /* move_ball()  */
 
 /*
  * move pad to left or right according to command 
  */
 int move_pad(const int ch)
 {
     int move;
 
     switch (ch) {
         case KEY_LEFT:
             move = -2;
             break;
         case KEY_RIGHT:
             move = 2;
             break;
         case 'q':
             quit_game(ch);
             break;
         case 'p':
             quit_game(ch);
             break;
         default:
             return 0;
     }
     attrset(A_REVERSE | COLOR_PAIR(BLOCK));
     mvaddstr(height - 2, pad, brick);
     pad = pad + move;
     if (pad < 0)
         pad = 0;
     if (pad > width - bw)
         pad = width - bw;
     attrset(A_NORMAL | COLOR_PAIR(BLOCK));
     mvaddstr(height - 2, pad, brick);
 
     refresh();
     return 0;
 }                            /* move_pad()  */
 
 /*
  * main 
  */
 int main(void)
 {
     initscr();
    start_color();
     init_pair(BLOCK, COLOR_BLACK, COLOR_RED);   /* for bricks and pad */
     init_pair(TXT, COLOR_CYAN, COLOR_BLACK);    /* for text strings */
     init_pair(BAR, COLOR_WHITE, COLOR_BLUE);    /* for bar */
     init_pair(BALL, COLOR_BLACK, COLOR_WHITE);  /* for ball */
     init_pair(CLEAR, COLOR_BLACK, COLOR_BLACK); /* to clear objects */
     noecho();
     raw();                   /* disable line buffering */
     timeout(100);
     cbreak();
     keypad(stdscr, TRUE);
     curs_set(0);
     getmaxyx(stdscr, height, width);
     signal(SIGWINCH, resizescr);
     if (height >= 20 && width >= 80) {
         print_msg(tStart, TRUE, TRUE);
         clear();
         draw_board();
         for (;;) {
             ch = getch();
             move_ball();
             if (ch != ERR)
                 move_pad(ch);
             if (state == OVER || state == QUIT)
                 break;
         }
     } else {                 /* screen too small, exit with complaint */
         state = QUIT;
         statestr = "Screen too small. Game aborted.";
     }
 
     sleep(1), flash();
     sleep(1), flash();
     sleep(1), flash();
     curs_set(1);
     keypad(stdscr, FALSE);
     nocbreak();
     notimeout(stdscr, TRUE);
     noraw();
     echo();
     endwin();
     puts(statestr);
     exit(0);
 }                            /* main()  */
 
 /*
  * Local variables:
  * tab-width: 4
  * indent-tabs-mode: nil
  * c-basic-offset: 4
  * End:
  * VIM: tw=80:sw=4:sts=4:fdm=marker
  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -