?? 16.txt
字號:
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
19 #include <stdio.h>
20 #include <string.h>
21 #include <ncurses.h>
22 #include <stdlib.h> /* for exit(), rand(), abs() */
23
24 #include <stddef.h> /* for NULL */
25 #include <time.h> /* for sleep() */
26 #include <signal.h> /* for SIGWINCH */
27
28 #define NORMAL 1 /* status of game */
29 #define PAUSE 2
30 #define OVER 3
31 #define QUIT 4
32 #define BLOCK 1 /* color pairs */
33 #define TXT 2
34 #define BAR 3
35 #define BALL 4
36 #define CLEAR 5
37
38 extern unsigned int sleep(unsigned int seconds);
39
40 /*
41 * globals
42 */
43 int speed = 10;
44 int cnt = 0; /* bricks yet remain on board */
45 int score = 0;
46 int level = 0;
47 int width = 40;
48 int height = 50; /* for the board */
49 short state = NORMAL; /* see define */
50 char *statestr = "Normal"; /* additional str to explain the game status */
51 const int bw = 7; /* brick width */
52 const char brick[] = " ";
53 int bricks[100][3];
54 int pad;
55 int ball[2];
56 int dir[2] = { 1, -1 };
57 int ch = 0; /* user command */
58
59 /*
60 +-- 62 lines: * text strings -------------------------------------------------------------------------------------------------------------
122 */
123
124 /*
125 * change sceen size, exit if too small
126 */
127 void resizescr(int sig)
128 {
129 statestr = "Screen resized.";
130 getmaxyx(stdscr, height, width);
131 } /* resizescr() */
132
133 /*
134 * print msg on center of screen, exit on pressing Y or N (key is true) or any
135 * char (key false)
136 */
137 bool print_msg(char *msg, bool y_n_key, bool clearmsg)
138 {
139 char *rest;
140 char *str[30];
141 char emptystr[width];
142 int line = 0;
143 int i;
144 int length;
145 int left;
146 int top;
147 char delimiters[] = "\n";
148
149 length = strlen(str[line] = strtok(msg, delimiters));
150 while ((rest = strtok(NULL, delimiters)) != NULL) {
151 line++;
152 if (length < strlen(rest))
153 length = strlen(rest);
154 str[line] = rest;
155 }
156
157 top = (height - line) / 2;
158 left = (width - length) / 2;
159 attrset(COLOR_PAIR(TXT));
160 for (i = 0; i <= line; i++) {
161 mvprintw(top++, left, "%s", str[i]);
162 }
164 refresh();
165
166 timeout(3000);
167 for (;;) {
168 ch = getch();
169 if (y_n_key)
170 break;
171 else {
172 if (ch == ERR || ch == 'y' || ch == 'Y') {
173 ch = 'Y';
174 break;
175 }
176 if (ch == 'n' || ch == 'N') {
177 ch = 'N';
178 break;
179 }
180 }
181 }
182
183 if (clearmsg) {
184 top = (height - line) / 2;
185 attrset(COLOR_PAIR(CLEAR));
186 for (i = 0; i < width; i++)
187 emptystr[i] = ' ';
188 for (i = 0; i <= line; i++) {
189 mvaddstr(top++, 0, emptystr);
190 }
191 refresh();
192 }
193 i = ch, ch = 0; /* clear input for later use */
194 timeout(100);
195
196 if (i == 'N')
197 return FALSE;
198 return TRUE;
199 } /* print_msg() */
200
201 /*
202 * draw pad, ball, bricks, and bar together
203 */
204 void draw_board(void)
205 {
206 int i, j;
207 char barstr[width];
208
209 level++;
210 cnt = 0;
211 dir[0] = 1, dir[1] = -1;
212
213 /* brick */
214 i = width % (bw + 1) / 2; /* width -1 + gap */
215 j = 1;
216 attrset(COLOR_PAIR(BLOCK));
217 for (;;) {
218 mvaddstr(j, i, brick);
219 bricks[cnt][0] = i;
220 bricks[cnt][1] = j;
221 bricks[cnt][2] = 1;
222 i = i + bw + 1;
223 cnt++;
224 if (i >= width - bw) {
225 if (cnt > 50)
226 break;
227 i = width % (bw + 1) / 2;
228 j += 2;
229 }
230 }
231 bricks[cnt][2] = -1; /* mark the end or all bricks */
232
233 if (level == 1) {
234 /* pad */
235 attrset(COLOR_PAIR(BLOCK));
236 pad = rand() % (width - bw - 1);
237 mvaddstr(height - 2, pad, brick);
238
239 /* bar */
240 for (i = 0; i < width; i++)
241 barstr[i] = ' ';
242 attrset(COLOR_PAIR(BAR));
243 mvaddstr(height - 1, 0, barstr);
244 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score,
245 level, statestr);
246 }
247
248 /* ball */
249 attrset(COLOR_PAIR(BALL));
250 ball[0] = pad, ball[1] = height - 3;
251 while (abs(ball[0] - pad) < 15)
252 ball[0] = rand() % (width - bw - 1);
253 mvaddstr(ball[1], ball[0], " ");
254
255 refresh();
256 } /* draw_board() */
257
258 /*
259 * try to stop game
260 */
261 void quit_game(const int ch)
262 {
263 if (ch == 'q') {
264 if (cnt < 0 /* do not want another level */
265 || (cnt > 0 && print_msg(tExit, FALSE, TRUE)) /* really meant to
266 * exit */
267 ) {
268 state = QUIT;
269 statestr = "Quit game";
270 }
271 } else if (ch == 'o') {
272 state = OVER;
273 statestr = "Game over";
274 print_msg(tOver, TRUE, FALSE);
275 } else if (state == PAUSE) {
276 state = NORMAL;
277 statestr = "Normal";
278 } else {
279 state = PAUSE;
280 statestr = "Pause";
281 }
282 /* bar */
283 attrset(A_NORMAL | COLOR_PAIR(BAR));
284 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score, level,
285 statestr);
286 refresh();
287 } /* quit_game() */
288
289 /*
290 * move the ball forward, turn if necessary, add scores, and quite if hit ground
291 */
292 void move_ball()
293 {
294 int i;
295
296 if (state != NORMAL)
297 return;
298
299 /* ball */
300 attrset(A_REVERSE | COLOR_PAIR(BALL));
301 mvaddstr(ball[1], ball[0], " ");
302 /* restore pad after hit */
303 attrset(A_NORMAL | COLOR_PAIR(BLOCK));
304 mvaddstr(height - 2, pad, brick);
305 ball[0] += dir[0], ball[1] += dir[1];
306 attrset(A_NORMAL | COLOR_PAIR(BALL));
307 mvaddstr(ball[1], ball[0], " ");
308
309 /* change direction */
310 if (ball[1] < 0)
311 dir[1] = -dir[1];
312 if (ball[0] < 0 || ball[0] > width)
313 dir[0] = -dir[0];
314
315 /* hit bricks */
316 attrset(A_REVERSE | COLOR_PAIR(BLOCK));
317 for (i = 0;; i++) {
318 if (bricks[i][2] == -1)
319 break;
320 if (bricks[i][2] == 0)
321 continue;
322 if (bricks[i][0] <= ball[0]
323 && bricks[i][0] + bw >= ball[0]
324 && bricks[i][1] == ball[1]
325 ) {
326 bricks[i][2] = 0;
327 /*
328 * tricky: make sure the direction is top-down
329 */
330 dir[1] = abs(dir[1]);
331 score += 10;
332 cnt--;
333 refresh();
334 mvaddstr(bricks[i][1], bricks[i][0], brick);
335 if (cnt <= 0) { /* another level */
336 if (print_msg(tGoon, FALSE, TRUE)) {
337 draw_board();
338 } else {
339 quit_game('q');
340 }
341 }
342 }
343 }
344
345 /* hit pad */
346 if (ball[1] == height - 2) {
347 if (ball[0] < pad || ball[0] > pad + bw)
348 quit_game('o');
349 /*
350 * for some reason, the ball may enter the pad, and change dir will not
351 * get it out, so use abs() to turn back
352 */
353 dir[1] = -abs(dir[1]);
354 if (ball[0] == pad || ball[0] == pad + bw) { /* on both ends */
355 dir[0] = -dir[0];
356 }
357 }
358
359 /* bar */
360 attrset(A_NORMAL | COLOR_PAIR(BAR));
361 mvprintw(height - 1, 0, "SCORE: %03d LEVEL: %d STATE: %-9s", score, level,
362 statestr);
364 refresh();
365 } /* move_ball() */
366
367 /*
368 * move pad to left or right according to command
369 */
370 int move_pad(const int ch)
371 {
372 int move;
373
374 switch (ch) {
375 case KEY_LEFT:
376 move = -2;
377 break;
378 case KEY_RIGHT:
379 move = 2;
380 break;
381 case 'q':
382 quit_game(ch);
383 break;
384 case 'p':
385 quit_game(ch);
386 break;
387 default:
388 return 0;
389 }
390 attrset(A_REVERSE | COLOR_PAIR(BLOCK));
391 mvaddstr(height - 2, pad, brick);
392 pad = pad + move;
393 if (pad < 0)
394 pad = 0;
395 if (pad > width - bw)
396 pad = width - bw;
397 attrset(A_NORMAL | COLOR_PAIR(BLOCK));
398 mvaddstr(height - 2, pad, brick);
399
400 refresh();
401 return 0;
402 } /* move_pad() */
403
404 /*
405 * main
406 */
407 int main(void)
408 {
409 initscr();
410 start_color();
411 init_pair(BLOCK, COLOR_BLACK, COLOR_RED); /* for bricks and pad */
412 init_pair(TXT, COLOR_CYAN, COLOR_BLACK); /* for text strings */
413 init_pair(BAR, COLOR_WHITE, COLOR_BLUE); /* for bar */
414 init_pair(BALL, COLOR_BLACK, COLOR_WHITE); /* for ball */
415 init_pair(CLEAR, COLOR_BLACK, COLOR_BLACK); /* to clear objects */
416 noecho();
417 raw(); /* disable line buffering */
418 timeout(100);
419 cbreak();
420 keypad(stdscr, TRUE);
421 curs_set(0);
422 getmaxyx(stdscr, height, width);
423 signal(SIGWINCH, resizescr);
425 if (height >= 20 && width >= 80) {
426 print_msg(tStart, TRUE, TRUE);
431 clear();
432 draw_board();
433 for (;;) {
434 ch = getch();
435 move_ball();
436 if (ch != ERR)
437 move_pad(ch);
438 if (state == OVER || state == QUIT)
439 break;
440 }
441 } else { /* screen too small, exit with complaint */
442 state = QUIT;
443 statestr = "Screen too small. Game aborted.";
444 }
445
446 sleep(1), flash();
447 sleep(1), flash();
448 sleep(1), flash();
449 curs_set(1);
450 keypad(stdscr, FALSE);
451 nocbreak();
452 notimeout(stdscr, TRUE);
453 noraw();
454 echo();
455 endwin();
456 puts(statestr);
457 exit(0);
458 } /* main() */
459
460 /*
461 * Local variables:
462 * tab-width: 4
463 * indent-tabs-mode: nil
464 * c-basic-offset: 4
465 * End:
466 * VIM: tw=80:sw=4:sts=4:fdm=marker
467 */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -