- 论坛徽章:
- 0
|
linux下面的C编程,我还是新手,请大家别笑话。
- /*
- * Brick & Ball
- * by Jerry Fleming <jerryfleming2006@gmail.com>
- *
- * This is a small game inspired from similar one in Motorola Mobile C289,
- * and my first REAL program in C :) Please tell me if you have a better
- * implementation or any suggestions.
- *
- * HISTORY:
- * 2006-10-25: third (current) version with c language
- * 2006-10-01: second version with tkinter
- * 2006-04-19: first version with curses
- *
- * TODO:
- * Nothing to do right now. :) If you have any ideas to improve or enhance it,
- * please contact me.
- */
- #include <stdio.h>
- #include <string.h>
- #include <ncurses.h>
- #include <stdlib.h> /* for exit(), rand(), abs() */
- #include <stddef.h> /* for NULL */
- #include <unistd.h> /* for sleep() */
- #include <signal.h> /* for SIGWINCH */
- #include <assert.h> /* for DEBUG */
- #define NORMAL 1 /* game status */
- #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
- /*
- * 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 */
- /*
- * text strings {{{
- */
- const char *tStart[] = {
- " ______ _ _ ___ ______ _ _ ",
- " (____ \\ (_) | | / _ \\ (____ \\ | | | ",
- " ____) ) ____ _ ____| | _ ( (_) ) ____) )_____| | | ",
- " | __ ( / ___) |/ ___) |_/ ) ) _ ( | __ ((____ | | | ",
- " | |__) ) | | ( (___| _ ( ( (/ \\ | |__) ) ___ | | | ",
- " |______/|_| |_|\\____)_| \\_) \\__/\\_) |______/\\_____|\\_)_) ",
- " ",
- " ",
- " ",
- " by Jerry Fleming <jerryfleming2006@gmail.com> ",
- " ",
- " ",
- " GAME STARTING! PRESS ANY KEY TO GO ON ... ",
- " ",
- " ------------------------------------------------------------ ",
- "| P: Pause / Resume <-, ->: Move Right / Left Y:Yes N: No | ",
- " ------------------------------------------------------------ ",
- ""
- };
- const char *tExit[] = {
- " 88888 88888",
- "88888888888 88 ad88888ba 88 8b d8 d8 88",
- "88 \"\" ,d d8\" \"8b 88 Y8, ,8P ,8P' 88",
- "88 88 \"\" a8P 88 Y8, ,8P d8\" 88",
- "88aaaaa 8b, ,d8 88 MM88MMM ,a8P\" 88 \"8aa8\" ,8P' 8b,dPPYba, 88",
- "88\"\"\"\"\" `Y8, ,8P' 88 88 d8\" 88 `88' d8\" 88P' `\"8a 88",
- "88 )888( 88 88 \"\" 88 88 ,8P' 88 88 88",
- "88 ,d8\" \"8b, 88 88, aa 88 88 d8\" 88 88 88",
- "88888888888 8P' `Y8 88 \"Y888 88 88 88 8P' 88 88 88",
- " 88888 88888",
- ""
- };
- const char *tOver[] = {
- " ,ad8888ba, 88",
- " d8\"' `\"8b 88",
- "d8' 88",
- "88 ,adPPYYba, 88,dPYba,,adPYba, ,adPPYba, ,adPPYba, 8b d8 ,adPPYba, 8b,dPPYba, 88",
- "88 88888 \"\" `Y8 88P' \"88\" \"8a a8P_____88 a8\" \"8a `8b d8' a8P_____88 88P' \"Y8 88",
- "Y8, 88 ,adPPPPP88 88 88 88 8PP\"\"\"\"\"\"\" 8b d8 `8b d8' 8PP\"\"\"\"\"\"\" 88 \"\"",
- " Y8a. .a88 88, ,88 88 88 88 \"8b, ,aa \"8a, ,a8\" `8b,d8' \"8b, ,aa 88 aa",
- " `\"Y88888P\" `\"8bbdP\"Y8 88 88 88 `\"Ybbd8\"' `\"YbbdP\"' \"8\" `\"Ybbd8\"' 88 88",
- ""
- };
- const char *tGoon[] = {
- " 88888 88888",
- " ,ad8888ba, ad88888ba 88 8b d8 d8 88",
- " d8\"' `\"8b d8\" \"8b 88 Y8, ,8P ,8P' 88",
- "d8' \"\" a8P 88 Y8, ,8P d8\" 88",
- "88 ,adPPYba, ,adPPYba, 8b,dPPYba, ,a8P\" 88 \"8aa8\" ,8P' 8b,dPPYba, 88",
- "88 88888 a8\" \"8a a8\" \"8a 88P' `\"8a d8\" 88 `88' d8\" 88P' `\"8a 88",
- "Y8, 88 8b d8 8b d8 88 88 \"\" 88 88 ,8P' 88 88 88",
- " Y8a. .a88 \"8a, ,a8\" \"8a, ,a8\" 88 88 aa 88 88 d8\" 88 88 88",
- " `\"Y88888P\" `\"YbbdP\"' `\"YbbdP\"' 88 88 88 88 88 8P' 88 88 88",
- " 88888 88888",
- ""
- };
- const char *tHelp =
- "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.";
- /*
- * string variables }}}
- */
- /*
- * change sceen size, exit if too small
- */
- void resizescr(int sig)
- {
- statestr = "Quit because screen resized.";
- state = QUIT;
- } /* resizescr() */
- /*
- * print msg on center of screen
- * y_n_key: exit on pressing Y or N (key is true) or any char (key false)
- * clearmsg: clear the msg window (when 1, or 2 and Y, or 3 and N)
- */
- bool print_msg(const char *msg[], const bool y_n_key, const int clearmsg)
- {
- WINDOW *txtwin = NULL;
- int length = 0;
- int tmplength = 0;
- int line = 0;
- int i;
- int left;
- int top;
- char emptymsg[width];
- for (;;) {
- tmplength = strlen(msg[line]);
- if (tmplength == 0)
- break;
- if (length < tmplength)
- length = tmplength;
- line++;
- }
- assert(length < width);
- assert(line != 0);
- top = (height - line) / 2;
- left = (width - length) / 2;
- txtwin = newwin(line, length, top, left);
- wattrset(txtwin, COLOR_PAIR(TXT));
- assert(txtwin != NULL);
- for (i = 0; i < line; i++) {
- mvwaddstr(txtwin, i, 0, msg[i]);
- }
- wrefresh(txtwin);
- 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 == 1
- || (clearmsg == 2 && ch == 'Y')
- || (clearmsg == 3 && ch == 'N')
- ) {
- for (i = 0; i < length; i++)
- emptymsg[i] = ' ';
- wattrset(txtwin, COLOR_PAIR(TXT));
- for (i = 0; i < line; i++) {
- mvwaddstr(txtwin, i, 0, emptymsg);
- }
- wrefresh(txtwin);
- delwin(txtwin);
- }
- 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, 3)) /* really meant to
- * exit */
- ) {
- state = QUIT;
- statestr = "Quit game";
- }
- } else if (ch == 'o') {
- state = OVER;
- statestr = "Game over";
- print_msg(tOver, TRUE, 0);
- } 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;
- int tmpball[] = { ball[0], ball[1] };
- 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);
- tmpball[0] += dir[0], tmpball[1] += dir[1];
- /* change direction */
- if (tmpball[1] < 0)
- dir[1] = -dir[1];
- if (tmpball[0] < 0 || tmpball[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] <= tmpball[0]
- && bricks[i][0] + bw >= tmpball[0]
- && bricks[i][1] == tmpball[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, 2)) {
- draw_board();
- } else {
- quit_game('q');
- }
- }
- }
- }
- /* hit pad */
- if (tmpball[1] == height - 2) {
- if (tmpball[0] < pad || tmpball[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 (tmpball[0] == pad || tmpball[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);
- ball[0] += dir[0], ball[1] += dir[1];
- attrset(A_NORMAL | COLOR_PAIR(BALL));
- mvaddstr(ball[1], ball[0], " ");
- refresh();
- } /* move_ball() */
- /*
- * move pad to left or right according to command
- */
- int move_pad(const int ch)
- {
- int move = 0;
- 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 */
- 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) {
- refresh();
- print_msg(tStart, TRUE, 0);
- 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();
- 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
- */
复制代码
编译:
- gcc -Wall -pedantic --std=c99 -g -o game game.c -lncurses
复制代码 |
|