pong game using ncurses

bounce2d2.c

  1 /*
  2  * bounce2d 1.0
  3  * bounce a character (default is 'o') around the screen
  4  *  defined by some parameters
  5  * user input: s slow down x component, S: slow y component
  6  *             f speed up x component, F: speed y component
  7  *             Q quit
  8  * blocks on read, but timer tick sends SIGALRM caught by ball_move
  9  * build: cc bounce2d.c set_ticker.c -lcurses -o bounce2d
 10     */
 11 #include <curses.h>
 12 #include <string.h>
 13 #include <signal.h>
 14 #include "bounce.h"
 15 
 16 struct ppball the_ball;
 17 
 18 /** the main loop **/
 19 
 20 //int flap_pos = RIGHT_EDGE / 2 - LEFT_EDGE;
 21 int flap_pos =0;
 22 int old_pos = 0;
 23 void set_up();
 24 void wrap_up();
 25 void move_flap();
 26 int bounce_or_lose(struct ppball *);
 27 
 28 int main()
 29 {
 30 //    printf("LEFT_EDGE: %d, RIGHT_EDGE: %d\n",LEFT_EDGE, RIGHT_EDGE);
 31 //    printf("TOP_EDGE: %d, BOT_EDGE: %d\n",TOP_ROW, BOT_ROW);
 32     int c;
 33     set_up();
 34     while (((c = getchar())) != 'Q')
 35     {
 36         if (c == 'f') the_ball.x_ttm--;
 37         else if (c == 's') the_ball.x_ttm++;
 38         else if (c == 'F') the_ball.y_ttm--;
 39         else if (c == 'S') the_ball.y_ttm++;
 40         else if (c == 'a'){
 41             if (flap_pos > LEFT_EDGE){
 42                 old_pos = flap_pos;
 43                 flap_pos -= FLAP_SPEED;
 44                 move_flap();
 45             }
 46         }else if (c == 'd'){
 47             if (flap_pos + (int)strlen(FLAP) < RIGHT_EDGE){
 48                 old_pos = flap_pos;
 49                 flap_pos += FLAP_SPEED;
 50                 move_flap();
 51             }
 52         }
 53     }
 54     wrap_up();
 55 //    printf("LINES: %d, COLS: %d\n",LINES, COLS);
 56     return 0;
 57 }
 58 
 59 void set_up()
 60     /*
 61      * init structure and other stuff
 62      */
 63 {
 64     void ball_move(int);
 65     the_ball.y_pos = Y_INIT;
 66     the_ball.x_pos = X_INIT;
 67     the_ball.y_ttg = the_ball.y_ttm = Y_TIM;
 68     the_ball.x_ttg = the_ball.x_ttm = X_TIM;
 69     the_ball.y_dir = 1;
 70     the_ball.x_dir = 1;
 71     the_ball.symbol = DFL_SYMBOL;
 72     the_ball.x_moved = the_ball.y_moved = false;
 73 
 74     initscr();
 75     noecho();
 76     crmode();
 77 
 78     signal(SIGINT, SIG_IGN);
 79     mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
 80     move_flap();
 81     signal(SIGALRM, ball_move);
 82     set_ticker(1000 / TICKS_PER_SEC);
 83 }
 84 
 85 void wrap_up()
 86 {
 87     set_ticker(0);
 88     endwin();
 89 }
 90 
 91 void move_flap()
 92 {
 93     move(BOT_ROW + 1, old_pos);
 94     addstr(FLAP); //FLAP is blank. Here it is used to clear its old existence.
 95 
 96     move(BOT_ROW + 1, flap_pos);
 97     standout();
 98     addstr(FLAP);
 99     standend();
100     refresh();
101 }
102 
103 void ball_move(int signum)
104 {
105     int y_cur, x_cur, moved;
106 
107     signal(SIGALRM, SIG_IGN);
108     x_cur = the_ball.x_pos;
109     y_cur = the_ball.y_pos;
110     moved = 0;
111 
112     if (the_ball.y_ttm > 0 &&  the_ball.y_ttg-- == 1){
113         the_ball.y_pos += the_ball.y_dir;  /* move */
114         the_ball.y_ttg = the_ball.y_ttm;   /* reset */
115         the_ball.y_moved = 1;
116         moved = 1;
117     }
118 
119     if (the_ball.x_ttm > 0 && the_ball.x_ttg-- == 1){
120         the_ball.x_pos += the_ball.x_dir;  /* move */
121         the_ball.x_ttg = the_ball.x_ttm;   /* reset */
122         the_ball.x_moved = 1;
123         moved = 1;
124     }
125 
126     if (moved){
127         mvaddch(y_cur, x_cur, BLANK);
128         mvaddch(y_cur, x_cur, BLANK);
129         mvaddch(the_ball.y_pos, the_ball.x_pos, the_ball.symbol);
130         if(bounce_or_lose(&the_ball)){
131 //            signal(SIGALRM, SIG_IGN);
132             move(LINES / 2, COLS / 2);
133             addstr("GAME OVER");
134             refresh();
135             return;
136         }
137         move(LINES-1, COLS-1);
138         if (the_ball.x_moved && the_ball.y_moved){
139             refresh();
140             the_ball.x_moved = the_ball.y_moved = false; /* reset */
141         }
142     }
143     signal(SIGALRM, ball_move);
144 }
145 
146 int bounce_or_lose(struct ppball *bp)
147     /*
148      * 1 lose
149      * 0 not lose
150      */
151 {
152     int return_val = 0;
153 
154     if (bp->y_pos == TOP_ROW){
155         bp->y_dir = 1;
156     }else if (bp->y_pos == BOT_ROW){
157         bp->y_dir = -1;
158         if (!(bp->x_pos >= flap_pos && bp->x_pos <= (flap_pos + (int)strlen(FLAP)))){
159             return_val = 1;
160         }
161     }
162 
163     if (bp->x_pos == LEFT_EDGE){
164         bp->x_dir = 1;
165     }else if (bp->x_pos == RIGHT_EDGE){
166         bp->x_dir = -1;
167     }
168     return return_val;
169 }

 

bounce.h

 

 1 #define BLANK ' '
 2 #define DFL_SYMBOL 'o'
 3 #define TOP_ROW 0
 4 #define BOT_ROW 20
 5 #define LEFT_EDGE 0
 6 #define RIGHT_EDGE 81
 7 #define X_INIT 3
 8 #define Y_INIT 5
 9 #define TICKS_PER_SEC 50
10 #define Y_TIM 8
11 #define X_TIM 8
12 #define FLAP "               " 
13 //#define FLAP_LEN 21
14 #define FLAP_SPEED 1
15 
16 struct ppball {
17     int x_ttg; // x 轴下次重画还要等待多少个计时器
18     int y_ttg; // y 轴下次重画还要等待多少个计时器
19     int x_ttm; // x 轴移动需要等待的信号间隔
20     int y_ttm; // y 轴移动絮叨等待的信号间隔
21     int y_pos;
22     int x_pos;
23     int y_dir;
24     int x_dir;
25     int x_moved;
26     int y_moved;
27     char symbol;
28 };

 

set_ticker.c

 1 #include    <stdio.h>
 2 #include        <sys/time.h>
 3 #include        <signal.h>
 4 #include    <stdlib.h>
 5 
 6 /*
 7  *      set_ticker.c
 8  *          set_ticker( number_of_milliseconds )
 9  *                   arranges for the interval timer to issue
10  *                   SIGALRM's at regular intervals
11  *          returns -1 on error, 0 for ok
12  *
13  *      arg in milliseconds, converted into micro seoncds
14  */
15 
16 
17 set_ticker( n_msecs )
18 {
19         struct itimerval new_timeset;
20         long    n_sec, n_usecs;
21 
22         n_sec = n_msecs / 1000 ;
23         n_usecs = ( n_msecs % 1000 ) * 1000L ;
24 
25         new_timeset.it_interval.tv_sec  = n_sec;        /* set reload  */
26         new_timeset.it_interval.tv_usec = n_usecs;      /* new ticker value */
27         new_timeset.it_value.tv_sec     = n_sec  ;      /* store this   */
28         new_timeset.it_value.tv_usec    = n_usecs ;     /* and this     */
29 
30     return setitimer(ITIMER_REAL, &new_timeset, NULL);
31 }

==================================================================================================== 

A different version:

  1 #include <curses.h>
  2 #include <sys/time.h>
  3 #include <signal.h>
  4  
  5 #define RIGHT COLS-1   /*球所能到达的当前屏幕最大水平范围*/
  6 #define BOTTOM LINES-1 /*球所能到达的当前屏幕最大垂直范围*/
  7 #define BOARD_LENGTH   10  /*挡板长度*/
  8 #define LEFT 0  /*当前屏幕的最左边*/
  9 #define TOP 0   /*当前屏幕的最上边*/
 10 char BALL= 'O';  /*球的形状*/
 11 char BLANK= ' ';  /*覆盖球走过的轨迹*/
 12  
 13 
 14 int left_board; /*挡板左侧坐标*/
 15 int right_board; /*挡板右侧坐标*/
 16 int is_lose=0;
 17 
 18 
 19 int hdir;   /*控制球水平运动的变量*/
 20 int vdir;   /*控制球垂直运动的变量*/
 21 int pos_X;  /*球的横坐标*/
 22 int pos_Y;  /*球的纵坐标*/
 23       
 24 int delay=100;
 25 void moveBall();
 26 void init();
 27 void control();
 28 
 29 int main()
 30 {
 31     //初始化 curses
 32     initscr();
 33     crmode();  /*中断模式*/
 34     noecho();  /*关闭回显*/
 35      
 36     move(6,28);
 37     attron(A_BOLD);
 38     addstr("Welcome to the BallGame!");
 39     move(8,20);
 40     attroff(A_BOLD);
 41     addstr("Help:");
 42     move(9,23);
 43     addstr("'N':Start a new game.");
 44     move(10,23);
 45     addstr("'Q':Quit game.");
 46     move(11,23);
 47     addstr("'KEY_LEFT' :Control baffle left  shift.");
 48     move(12,23);
 49     addstr("'KEY_RIGHT':Control baffle right shift.");
 50     move(13,23);
 51     addstr("'KEY_UP'   :Control of the ball speed.");
 52     move(14,23);
 53     addstr("'KEY_DOWN' :Control of the ball reducer.");
 54     int flag=1;
 55     char choice;
 56     move(16,24);
 57     addstr("Please choose your choice!(n/q):");
 58     refresh();
 59     choice=getch();
 60     while(flag){
 61         if(choice=='q'||choice=='Q'||choice=='n'||choice=='N')
 62              flag=0;
 63         else  choice=getch();
 64     }
 65     if(choice=='n'||choice=='N'){    /*开始游戏*/
 66         clear();
 67         move(10,25);
 68         addstr("BallGame will start! Are you ready?");
 69         refresh();
 70         sleep(3);
 71         control();
 72     }
 73     else if(choice=='q'||choice=='Q'){   /*退出游戏*/
 74         clear();
 75         move(10,25);
 76         addstr("You quit the game successfully!");
 77         refresh();
 78         sleep(3);
 79         endwin();
 80     }
 81     endwin();  /*结束 curses*/
 82     return 0;
 83 }
 84  
 85 void init(){
 86     int i,j;
 87     clear();
 88     if(start_color()==OK){  /*改变球和挡板的颜色*/
 89         attron(A_BOLD);  /*打开粗体*/
 90         init_pair(1,COLOR_YELLOW,COLOR_BLACK);
 91         attron(COLOR_PAIR(1));
 92     }
 93     //初始球
 94     pos_X =22;  /*球初始的横坐标*/
 95     pos_Y = BOTTOM-1;  /*球初始的纵坐标*/
 96     //初始化球的运动方向,朝右上方运动
 97     hdir=1; 
 98     vdir=-1;
 99  
100     //初始挡板
101     left_board=20;
102     right_board=left_board+BOARD_LENGTH;
103     for(i=left_board;i<=right_board;i++){  /*显示挡板*/
104         move(BOTTOM,i);
105         addch('-');
106     }
107  
108     //初始刷新时间
109     signal(SIGALRM,moveBall);
110     set_ticker(delay);
111  
112     keypad(stdscr,TRUE);  /*打开 keypad 键盘响应*/
113     attroff(A_BLINK);     /*关闭 A_BLINK 属性*/
114      
115     is_lose=0;
116     move(pos_Y,pos_X);
117     addch(BALL);
118     move(LINES-1, COLS-1);
119     refresh();
120     usleep(100000);  /*睡眠*/
121     move(LINES-1,COLS-1);
122     refresh();
123 }
124  
125 void moveBall(){
126     if(is_lose) return;
127     signal(SIGALRM,moveBall);
128     move(pos_Y,pos_X);
129     addch(BLANK);
130     pos_X += hdir;
131     pos_Y += vdir;
132     //改变球的方向时
133     if(pos_X >= RIGHT) { /*当球横坐标大于右边边缘时,球反弹朝左运动*/
134         hdir = -1;
135         beep();   /*球撞墙时,发出声音*/
136     }
137     if(pos_X <= LEFT)  { /*当球横坐标大于左边边缘时,球反弹朝右运动*/
138         hdir = 1;
139         beep();  /*球撞墙时,发出声音*/
140     }
141     if(pos_Y <= TOP)   { /*当球纵坐标大于顶部边缘时,球反弹朝下运动*/
142         vdir = 1;
143         beep();  /*球撞墙时,发出声音*/
144     }
145  
146     //当球在底部的时候进行额外的处理
147     if(pos_Y >= BOTTOM-1){
148         if(pos_X>=left_board&&pos_X<=right_board)  /*球在挡板处*/
149             vdir=-1;
150         else{    /*球不在挡板处*/
151             is_lose=1;
152             move(pos_Y,pos_X);
153             addch(BALL);
154             move(LINES-1, COLS-1);
155             refresh();
156             usleep(delay*1000);  /*睡眠*/
157             move(pos_Y,pos_X);
158             addch(BLANK);
159             pos_X += hdir;
160             pos_Y += vdir;
161             move(pos_Y,pos_X);
162             addch(BALL);
163             move(LINES-1, COLS-1);
164             refresh();
165         }
166     }
167     //不改变球的方向时
168     move(pos_Y,pos_X);
169     addch(BALL);
170     move(LINES-1, COLS-1);
171     refresh();
172 }
173 void control(){
174     init();
175     int cmd;
176     while (1)
177     {     
178         if(!is_lose){
179             cmd=getch();
180             if(cmd=='q'||cmd=='Q'||cmd==27) break;  //强制退出游戏
181             //挡板左移
182             if(cmd==KEY_LEFT){
183                 if(left_board>0){
184                     move(BOTTOM,right_board);
185                     addch(' ');
186                     right_board--;
187                     left_board--;                     
188                     move(BOTTOM,left_board);
189                     addch('-');
190                     move(BOTTOM,RIGHT);
191                     refresh();
192                 }
193             }     
194             //挡板右移
195             else if(cmd==KEY_RIGHT){
196                 if(right_board<RIGHT){
197                     move(BOTTOM,left_board);
198                     addch(' ');
199                     right_board++;
200                     left_board++;
201                     move(BOTTOM,right_board);
202                     addch('-');
203                     move(BOTTOM,RIGHT);
204                     refresh();
205                 }
206             }
207             //给球加速
208             else if(cmd==KEY_UP){   
209                 delay/=2;     
210                 set_ticker(delay);
211             }
212             //给球减速
213             else if(cmd==KEY_DOWN){  
214                 delay*=2;
215                 set_ticker(delay);
216             }
217          
218         }
219         else{
220             //输掉球后的处理
221             int flag=1;
222             char choice;
223             move(8,15);
224             addstr("Game Over!try again?(y/n):");
225             refresh();
226             choice=getch();
227  
228             while(flag){
229                 if(choice=='y'||choice=='Y'||choice=='n'||choice=='N')
230                      flag=0;
231                 else  choice=getch();
232             }
233             if(choice=='y'||choice=='Y'){  /*游戏重新开始*/
234                     delay=100; /*恢复球的初始速度*/
235                     init();
236                     continue;
237             }
238             else if(choice=='n'||choice=='N'){   /*结束游戏*/
239                     break;
240             }
241         }
242     }
243 }
244 //设置定时器
245 int set_ticker(int n_msecs){
246     struct itimerval new_timeset;     
247     long n_sec,n_usecs;
248     n_sec=n_msecs/1000;
249     n_usecs=(n_msecs%1000)*1000L;
250     new_timeset.it_interval.tv_sec=n_sec;
251     new_timeset.it_interval.tv_usec=n_usecs;
252     new_timeset.it_value.tv_sec=n_sec;
253     new_timeset.it_value.tv_usec=n_usecs;
254     return setitimer(ITIMER_REAL,&new_timeset,NULL); 
255 }
View Code

 

posted @ 2015-07-12 16:48  Ryan in C++  阅读(567)  评论(0编辑  收藏  举报